Spring security 自定义登录与权限控制
2016-11-18 15:12
525 查看
一、先说必要的配置文件:
1、web.xml文件添加上
2、application-context.xml配置文件
在application-context配置文件中加入spring security配置文件的引用:
3、securityConfig.xml文件:
4、toolbox.xml文件:
这样在vm界面中就可以直接使用啦~
二、配置文件中的hasAnyRole()方法和UserDetailService的实现
1.SecurityVelocity.java:
2.UserDetailServiceImpl.java
这个类主要是在登录时调用来设置用户权限信息的。
三:自己登录逻辑与springsecurity结合
四、登录页login.vm
五、注意点:
用spring security默认的登录,登录页的form的action="/manage/j_spring_security_check"这样写,默认会调用UsernamePasswordAuthenticationFilter中的验证信息。
自己写的登录逻辑主要是要把验证信息写入到spring security的上下文中,三行主要的代码如下:
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(mobile, password);
//调用loadUserByUsername设置权限信息
Authentication authentication = authenticationManager.authenticate(authRequest);
SecurityContextHolder.getContext().setAuthentication(authentication);
对于自动登录的,需要把权限也放入spring security上下文中,但是生成 UsernamePasswordAuthenticationToken对象需要密码的明文,这里我是把它放在缓存中,是自动登录的直接从缓存中取出来放进spring security上下文中。
final UserVo Vo = getLoginUser(request);
if (userVo != null && userVo.getId() != null) {
//登录信息有效需要将权限信息放入SecurityContextHolder的上下文信息中心,否则可能会造成循环重定向,服务器报错。
Authentication authentication = (Authentication) request.getAttribute(CommonConstants.USER_AUTH);
SecurityContextHolder.getContext().setAuthentication(authentication);
// redirect to homepage
return "redirect:/";
}
自动登录开始把权限也放入spring security上下文中,结果出现了循环重定向,是因为之前选择了自动登录,则if条件为true,这时重定向的/login,又开始执行登录页面的代码,造成了重定向死循环。
看到别人写的一篇好文,有助于理解:http://blog.csdn.net/zy_cookie/article/details/49535413
1、web.xml文件添加上
<!-- Spring Security 权限框架 --> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class> org.springframework.web.filter.DelegatingFilterProxy </filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
2、application-context.xml配置文件
在application-context配置文件中加入spring security配置文件的引用:
<?xml version="1.0" encoding="UTF-8"?> <beans ......> <bean> <!-- Connection Info --> ......此处省略 </bean><bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"> ...... <!-- if you want to use the Spring Velocity macros, set this property to true --> <property name="exposeSpringMacroHelpers" value="true"/> <property name="contentType" value="text/html;charset=UTF-8"></property> <property name="toolboxConfigLocation"> <value>/WEB-INF/toolbox.xml</value> </property> </bean><import resource="/securityConfig.xml"/></beans>
3、securityConfig.xml文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:security="http://www.springframework.org/schema/security" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd"> <!--use-expressions="true" 的意思是开启表达式 , access-denied-page的意思是,当验证权限失败后会跳转到的页面 --> <security:http auto-config="true" use-expressions="true" access-denied-page="/denied"> <!-- 对所有的资源,进行权限的设置访问--><!-- 所有人都可以访问资源文件 --><security:intercept-url pattern="/login" access="permitAll" /><security:intercept-url pattern="/logout" access="permitAll" /><security:intercept-url pattern="/slr/prd/**" access="hasAnyRole('SHOW_PRD','ADD_PRD','MOD_PRD','DEL_PRD')" /><security:intercept-url pattern="/slr/order/**" access="hasAnyRole('SHOW_ORD','CONFIRM_ORD','CANCEL_ORD')" /><security:intercept-url pattern="/slr/mgm/**" access="hasAnyRole('SHOW_ACCT','ADD_ACCT','MOD_ACCT','DEL_ACCT')" /><!-- 配置登录页面为login ,登录成功默认跳转到welcome --><security:form-login login-page="/login" default-target-url="/welcome"/><security:session-management session-authentication-strategy-ref="concurrentSessionControlStrategy" /></security:http><!--<!– 阻止多端登录 –>--> <bean id="concurrentSessionControlStrategy" class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy"> <constructor-arg name="sessionRegistry" ref="sessionRegistry" /> <property name="maximumSessions" value="1"></property> </bean> <bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" /> <!-- 配置一个认证管理器 --> <security:authentication-manager alias="authenticationManager"> <!-- 使用自定义的UserDetailService --> <security:authentication-provider user-service-ref="userDetailsService"> <security:password-encoder ref="passwordEncoder"/> </security:authentication-provider> </security:authentication-manager> <!--<!– 对密码进行MD5编码 –>--> <bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" id="passwordEncoder"/> <!-- 通过 userDetailsService,Spring会自动的定义用户的访问级别. --> <bean id="userDetailsService" class="com.security.UserDetailsServiceImpl" /></beans>
4、toolbox.xml文件:
<toolbox> <data type="string"> <key>version</key> <value>1.3</value> </data> ...... <tool> <key>sec</key> <scope>request</scope> <class>com.security.SecurityVelocity</class> </tool> </toolbox>
这样在vm界面中就可以直接使用啦~
#if($sec.hasAnyRole("SHOW_PRD","ADD_PRD","MOD_PRD","DEL_PRD")) <h2>商品管理</h2> <ul> <li><a href="/slr/prd/list">商品管理</a></li> </ul> #end
二、配置文件中的hasAnyRole()方法和UserDetailService的实现
1.SecurityVelocity.java:
public class SecurityVelocity { public boolean hasAnyRole(String ...roles) { return isRole(roles); } /*** * 前端传入数组参数 * @param viewRole 可变数组 1个或者多个 * @return 是否有权限 */ private boolean isRole(String ...roles){ /** 前端数组为空 */ if(null == roles || roles.length <= 0){ return false; } /** 获取当前用户登录对象 */ UserDetails userDetails = null; try { userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); } catch (Exception e) { return false; } if(null == userDetails){ return false; } /** 获取当前用户登录对象所有权限 */ Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities(); if(null == authorities){ return false; } boolean flag = false; Iterator<? extends GrantedAuthority> iter = authorities.iterator(); while (iter.hasNext()) { GrantedAuthority grantedAuthority = iter.next(); /**遍历前端列表的所有角色*/ for (String vr : roles) { if(vr.equals(grantedAuthority.getAuthority())){ flag = true; break; } } if (flag) break; // 已经匹配上角色了则不再需要匹配其它角色。 } return flag; } }
2.UserDetailServiceImpl.java
public class UserDetailsServiceImpl implements UserDetailsService { @Autowired private UserAuthService userAuthService; @Autowired private UserService userService; public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { User securityUser = null; UserVo mngVo = userService.getSellerByMobile(userName); //权限设置 Collection<GrantedAuthority> grantedAuthorities = this.getGrantedAuthorities(mngVo); boolean enables = true; boolean accountNonExpired = true; boolean credentialsNonExpired = true; boolean accountNonLocked = true; securityUser = new User(mngVo.getId().toString(), mngVo.getPassword(), enables, accountNonExpired, credentialsNonExpired, accountNonLocked, grantedAuthorities); return securityUser; } /** * 根据用户获取该用户拥有的权限 * @param user 当前用户 * @return 用户角色集合 */ private Set<GrantedAuthority> getGrantedAuthorities(SellerVo user) { Set<GrantedAuthority> grantedAuthorities = new HashSet<GrantedAuthority>(); if(null != user){ List<AuthorityVo> auths = userAuthService.getUserRoleListByUserId(user.getId()); if(null != auths && auths.size() > 0 ) { for(AuthorityVo auth : auths) { grantedAuthorities.add(new SimpleGrantedAuthority(auth.getCode()+"")); } } } return grantedAuthorities; } }
这个类主要是在登录时调用来设置用户权限信息的。
三:自己登录逻辑与springsecurity结合
public class LoginController extends BaseController { ...... // show login page @RequestMapping("login") public String index(Model model, HttpServletRequest request, HttpServletResponse response) { // 判断登录状态是否还有效,有效的话自动登录 final UserVo Vo = getLoginUser(request);if (userVo != null && userVo.getId() != null) { //登录信息有效需要将权限信息放入SecurityContextHolder的上下文信息中心,否则可能会造成循环重定向,服务器报错。Authentication authentication = (Authentication) request.getAttribute(CommonConstants.USER_AUTH); SecurityContextHolder.getContext().setAuthentication(authentication); // redirect to homepage return "redirect:/"; }//返回登录页 return LOGIN; } // do login action @RequestMapping("do_login") public String doLogin(Model model, HttpServletResponse response, HttpServletRequest request, String mobile, String password) { log.info("User input data: mobile = " + mobile); if (StringUtils.isEmpty(mobile) || StringUtils.isEmpty(password)) { model.addAttribute("msg", "请输入手机号和密码!"); return INDEX; } ...... try { UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(mobile, password);//调用loadUserByUsername设置权限信息Authentication authentication = authenticationManager.authenticate(authRequest);SecurityContextHolder.getContext().setAuthentication(authentication); log.info("恭喜用户 " + mobile() + " 登录成功。"); ......response.sendRedirect('上一次访问的页面或welcome');} catch (IOException ex) {
log.warn("Error happened");
}
return INDEX;
四、登录页login.vm
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录页</title>......</head><body> <div> <p>登录</p> </div> <div> <div> <form id="loginForm" name="loginForm" action="/do_login" METHOD="post" > <h2><!-- a href="$!{base}/register">免费注册</a -->商家登录</h2> <p id="y_lg_02">$!{msg}</p> <div><input type="text" placeholder="手机号" value="$!{mobile}"/></div> <div><input type="password" placeholder="密码" value="$!{password}"/></div> <p><input type="checkbox"/><em>自动登录</em></p> <input type="submit" value="立即登录"/> </form> </div> </div></body></html>
五、注意点:
用spring security默认的登录,登录页的form的action="/manage/j_spring_security_check"这样写,默认会调用UsernamePasswordAuthenticationFilter中的验证信息。
自己写的登录逻辑主要是要把验证信息写入到spring security的上下文中,三行主要的代码如下:
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(mobile, password);
//调用loadUserByUsername设置权限信息
Authentication authentication = authenticationManager.authenticate(authRequest);
SecurityContextHolder.getContext().setAuthentication(authentication);
对于自动登录的,需要把权限也放入spring security上下文中,但是生成 UsernamePasswordAuthenticationToken对象需要密码的明文,这里我是把它放在缓存中,是自动登录的直接从缓存中取出来放进spring security上下文中。
final UserVo Vo = getLoginUser(request);
if (userVo != null && userVo.getId() != null) {
//登录信息有效需要将权限信息放入SecurityContextHolder的上下文信息中心,否则可能会造成循环重定向,服务器报错。
Authentication authentication = (Authentication) request.getAttribute(CommonConstants.USER_AUTH);
SecurityContextHolder.getContext().setAuthentication(authentication);
// redirect to homepage
return "redirect:/";
}
自动登录开始把权限也放入spring security上下文中,结果出现了循环重定向,是因为之前选择了自动登录,则if条件为true,这时重定向的/login,又开始执行登录页面的代码,造成了重定向死循环。
看到别人写的一篇好文,有助于理解:http://blog.csdn.net/zy_cookie/article/details/49535413
相关文章推荐
- spring security 自定义登录 权限 数据库
- java中自定义Spring Security权限控制管理示例(实战篇)
- spring security 使用(将权限信息放入数据库中,并自定义登录认证)
- 自定义Spring Security权限控制管理(实战篇)
- spring boot系列--spring security (基于数据库)登录和权限控制
- Spring security实现登录验证+权限控制
- spring security控制权限的几种方法
- [WCF权限控制]利用WCF自定义授权模式提供当前Principal[实例篇]
- ASP.NET 框架 之HttpModule 例程:实现登录控制和权限控制
- BasePage类+Session通用用户登录权限控制
- spring security 3 中使用自定义数据库来设置权限
- 基于struts2拦截器的权限控制系统2——基于自定义JSP标签的前台html元素控制
- [WCF权限控制]利用WCF自定义授权模式提供当前Principal[原理篇]
- 在struts中使用拦截器(Interceptor)控制登录和权限
- ASP.NET 框架 之HttpModule 例程:实现登录控制和权限控制
- WCF4.0 —— Routing Service 自定义Filter控制访问权限
- [WCF权限控制]WCF自定义授权体系详解[原理篇]
- 细粒度 自定义注解 权限控制具体实现
- 权限控制的自定义SharePoint文档库/列表项菜单
- spring security 3 中使用自定义数据库来设置权限