sprin-security之二(如何进行连接数据库)
spring security使用分类:
本文面向读者:
spring security的简单原理:
spring security使用实现(基于spring security3.1.4):
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!--加载Spring XML配置文件 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:securityConfig.xml </param-value> </context-param> <!-- Spring Secutiry3.1的过滤器链配置 --> <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> <!-- Spring 容器启动监听器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!--系统欢迎页面 --> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
上面那个配置不用多说了吧
<?xml version="1.0" encoding="UTF-8"?> <b:beans xmlns="http://www.springframework.org/schema/security" xmlns:b="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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.1.xsd"> <!--登录页面不过滤 --> <http pattern="/login.jsp" security="none" /> <http access-denied-page="/accessDenied.jsp"> <form-login login-page="/login.jsp" /> <!--访问/admin.jsp资源的用户必须具有ROLE_ADMIN的权限 --> <!-- <intercept-url pattern="/admin.jsp" access="ROLE_ADMIN" /> --> <!--访问/**资源的用户必须具有ROLE_USER的权限 --> <!-- <intercept-url pattern="/**" access="ROLE_USER" /> --> <session-management> <concurrency-control max-sessions="1" error-if-maximum-exceeded="false" /> </session-management> <!--增加一个filter,这点与 Acegi是不一样的,不能修改默认的filter了, 这个filter位于FILTER_SECURITY_INTERCEPTOR之前 --> <custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR" /> </http> <!--一个自定义的filter,必须包含 authenticationManager,accessDecisionManager,securityMetadataSource三个属性, 我们的所有控制将在这三个类中实现,解释详见具体配置 --> <b:bean id="myFilter" class="com.erdangjiade.spring.security.MyFilterSecurityInterceptor"> <b:property name="authenticationManager" ref="authenticationManager" /> <b:property name="accessDecisionManager" ref="myAccessDecisionManagerBean" /> <b:property name="securityMetadataSource" ref="securityMetadataSource" /> </b:bean> <!--验证配置,认证管理器,实现用户认证的入口,主要实现UserDetailsService接口即可 --> <authentication-manager alias="authenticationManager"> <authentication-provider user-service-ref="myUserDetailService"> <!--如果用户的密码采用加密的话 <password-encoder hash="md5" /> --> </authentication-provider> </authentication-manager> <!--在这个类中,你就可以从数据库中读入用户的密码,角色信息,是否锁定,账号是否过期等 --> <b:bean id="myUserDetailService" class="com.erdangjiade.spring.security.MyUserDetailService" /> <!--访问决策器,决定某个用户具有的角色,是否有足够的权限去访问某个资源 --> <b:bean id="myAccessDecisionManagerBean" class="com.erdangjiade.spring.security.MyAccessDecisionManager"> </b:bean> <!--资源源数据定义,将所有的资源和权限对应关系建立起来,即定义某一资源可以被哪些角色访问 --> <b:bean id="securityMetadataSource" class="com.erdangjiade.spring.security.MyInvocationSecurityMetadataSource" /> </b:beans>
其实所有配置都在<http></http>里面,首先这个版本的spring security不支持了filter=none的配置了,改成了独立的<http pattern="/login.jsp" security="none"/>,里面你可以配登陆页面、权限不足的返回页面、注销页面等,上面那些配置,我注销了一些资源和权限的对应关系,笔者这里不需要在这配死它,可以自己写拦截器来获得资源与权限的对应关系。
MyUserDetailService:
package com.erdangjiade.spring.security; import java.util.ArrayList; import java.util.Collection; import org.springframework.dao.DataAccessException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.GrantedAuthorityImpl; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; public class MyUserDetailService implements UserDetailsService { //登陆验证时,通过username获取用户的所有权限信息, //并返回User放到spring的全局缓存SecurityContextHolder中,以供授权器使用 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { Collection<GrantedAuthority> auths=new ArrayList<GrantedAuthority>(); GrantedAuthorityImpl auth2=new GrantedAuthorityImpl("ROLE_ADMIN"); GrantedAuthorityImpl auth1=new GrantedAuthorityImpl("ROLE_USER"); if(username.equals("lcy")){ auths=new ArrayList<GrantedAuthority>(); auths.add(auth1); auths.add(auth2); } User user = new User(username, "lcy", true, true, true, true, auths); return user; } }
其中UserDetailsService接口是spring提供的,必须实现的。别看这个类只有一个方法,而且这么简单,其中内涵玄机。
package com.erdangjiade.spring.security; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.springframework.security.access.SecurityMetadataSource; import org.springframework.security.access.intercept.AbstractSecurityInterceptor; import org.springframework.security.access.intercept.InterceptorStatusToken; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter { //配置文件注入 private FilterInvocationSecurityMetadataSource securityMetadataSource; //登陆后,每次访问资源都通过这个拦截器拦截 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { FilterInvocation fi = new FilterInvocation(request, response, chain); invoke(fi); } public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() { return this.securityMetadataSource; } public Class<? extends Object> getSecureObjectClass() { return FilterInvocation.class; } public void invoke(FilterInvocation fi) throws IOException, ServletException { //fi里面有一个被拦截的url //里面调用MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限 //再调用MyAccessDecisionManager的decide方法来校验用户的权限是否足够 InterceptorStatusToken token = super.beforeInvocation(fi); try { //执行下一个拦截器 fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); } finally { super.afterInvocation(token, null); } } public SecurityMetadataSource obtainSecurityMetadataSource() { return this.securityMetadataSource; } public void setSecurityMetadataSource( FilterInvocationSecurityMetadataSource newSource) { this.securityMetadataSource = newSource; } public void destroy() { } public void init(FilterConfig arg0) throws ServletException { } }
继承AbstractSecurityInterceptor、实现Filter是必须的。
package com.erdangjiade.spring.security; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.SecurityConfig; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; import com.erdangjiade.spring.security.tool.AntUrlPathMatcher; import com.erdangjiade.spring.security.tool.UrlMatcher; public class MyInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource { private UrlMatcher urlMatcher = new AntUrlPathMatcher(); private static Map<String, Collection<ConfigAttribute>> resourceMap = null; //tomcat启动时实例化一次 public MyInvocationSecurityMetadataSource() { loadResourceDefine(); } //tomcat开启时加载一次,加载所有url和权限(或角色)的对应关系 private void loadResourceDefine() { resourceMap = new HashMap<String, Collection<ConfigAttribute>>(); Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>(); ConfigAttribute ca = new SecurityConfig("ROLE_USER"); atts.add(ca); resourceMap.put("/index.jsp", atts); Collection<ConfigAttribute> attsno =new ArrayList<ConfigAttribute>(); ConfigAttribute cano = new SecurityConfig("ROLE_NO"); attsno.add(cano); resourceMap.put("/other.jsp", attsno); } //参数是要访问的url,返回这个url对于的所有权限(或角色) public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException { // 将参数转为url String url = ((FilterInvocation)object).getRequestUrl(); Iterator<String>ite = resourceMap.keySet().iterator(); while (ite.hasNext()) { String resURL = ite.next(); if (urlMatcher.pathMatchesUrl(resURL, url)) { return resourceMap.get(resURL); } } return null; } public boolean supports(Class<?>clazz) { return true; } public Collection<ConfigAttribute> getAllConfigAttributes() { return null; } }
实现FilterInvocationSecurityMetadataSource接口也是必须的。
package com.erdangjiade.spring.security.tool; public interface UrlMatcher{ Object compile(String paramString); boolean pathMatchesUrl(Object paramObject, String paramString); String getUniversalMatchPattern(); boolean requiresLowerCaseUrl(); }
package com.erdangjiade.spring.security.tool; import org.springframework.util.AntPathMatcher; import org.springframework.util.PathMatcher; public class AntUrlPathMatcher implements UrlMatcher { private boolean requiresLowerCaseUrl; private PathMatcher pathMatcher; public AntUrlPathMatcher() { this(true); } public AntUrlPathMatcher(boolean requiresLowerCaseUrl) { this.requiresLowerCaseUrl = true; this.pathMatcher = new AntPathMatcher(); this.requiresLowerCaseUrl = requiresLowerCaseUrl; } public Object compile(String path) { if (this.requiresLowerCaseUrl) { return path.toLowerCase(); } return path; } public void setRequiresLowerCaseUrl(boolean requiresLowerCaseUrl){ this.requiresLowerCaseUrl = requiresLowerCaseUrl; } public boolean pathMatchesUrl(Object path, String url) { if (("/**".equals(path)) || ("**".equals(path))) { return true; } return this.pathMatcher.match((String)path, url); } public String getUniversalMatchPattern() { return"/**"; } public boolean requiresLowerCaseUrl() { return this.requiresLowerCaseUrl; } public String toString() { return super.getClass().getName() + "[requiresLowerCase='" + this.requiresLowerCaseUrl + "']"; } }
然后MyAccessDecisionManager类的实现:
package com.erdangjiade.spring.security; import java.util.Collection; import java.util.Iterator; import org.springframework.security.access.AccessDecisionManager; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.SecurityConfig; import org.springframework.security.authentication.InsufficientAuthenticationException; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; public class MyAccessDecisionManager implements AccessDecisionManager { //检查用户是否够权限访问资源 //参数authentication是从spring的全局缓存SecurityContextHolder中拿到的,里面是用户的权限信息 //参数object是url //参数configAttributes所需的权限 public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { if(configAttributes == null){ return; } Iterator<ConfigAttribute> ite=configAttributes.iterator(); while(ite.hasNext()){ ConfigAttribute ca=ite.next(); String needRole=((SecurityConfig)ca).getAttribute(); for(GrantedAuthority ga : authentication.getAuthorities()){ if(needRole.equals(ga.getAuthority())){ return; } } } //注意:执行这里,后台是会抛异常的,但是界面会跳转到所配的access-denied-page页面 throw new AccessDeniedException("no right"); } public boolean supports(ConfigAttribute attribute) { return true; } public boolean supports(Class<?>clazz) { return true; } }
接口AccessDecisionManager也是必须实现的。
剩下的页面代码
<%@page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPEhtmlPUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>登录</title>
</head>
<body>
<form action ="j_spring_security_check" method="POST">
<table>
<tr>
<td>用户:</td>
<td><input type ='text' name='j_username'></td>
</tr>
<tr>
<td>密码:</td>
<td><input type ='password' name='j_password'></td>
</tr>
<tr>
<td><input name ="reset" type="reset"></td>
<td><input name ="submit" type="submit"></td>
</tr>
</table>
</form>
</body>
</html>
index.jsp:
<%@page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@taglib prefix="sec" uri="http://www.springframework.org/security/tags"%> <!DOCTYPEHTMLPUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'index.jsp' starting page</title> </head> <body> <h3>这是首页</h3>欢迎 <sec:authentication property ="name"/> ! <br> <a href="admin.jsp">进入admin页面</a> <a href="other.jsp">进入其它页面</a> </body> </html>
admin.jsp:
<%@page language="java" import="java.util.*" pageEncoding="utf-8"%> <!DOCTYPEHTMLPUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'admin.jsp' starting page</title> </head> <body> 欢迎来到管理员页面. <br> </body> </html>
accessDenied.jsp:
<%@page language="java" import="java.util.*" pageEncoding="utf-8"%> <!DOCTYPEHTMLPUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'admin.jsp' starting page</title> </head> <body> 欢迎来到管理员页面. <br> </body> </html>
other.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'other.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <h3>这里是Other页面</h3> </body> </html>
补充:
(2014年11月21日第一次补充):
第一点:
第二点:
package com.lcy.bookcrossing.springSecurity; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.Resource; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.SecurityConfig; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; import com.lcy.bookcrossing.bean.RoleUrlResource; import com.lcy.bookcrossing.dao.IRoleUrlResourceDao; import com.lcy.bookcrossing.springSecurity.tool.AntUrlPathMatcher; import com.lcy.bookcrossing.springSecurity.tool.UrlMatcher; public class MyInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource { private UrlMatcher urlMatcher = new AntUrlPathMatcher(); // private static Map<String, Collection<ConfigAttribute>> resourceMap = null; //将所有的角色和url的对应关系缓存起来 private static List<RoleUrlResource> rus = null; @Resource private IRoleUrlResourceDao roleUrlDao; //tomcat启动时实例化一次 public MyInvocationSecurityMetadataSource() { // loadResourceDefine(); } //tomcat开启时加载一次,加载所有url和权限(或角色)的对应关系 /*private void loadResourceDefine() { resourceMap = new HashMap<String, Collection<ConfigAttribute>>(); Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>(); ConfigAttribute ca = new SecurityConfig("ROLE_USER"); atts.add(ca); resourceMap.put("/index.jsp", atts); Collection<ConfigAttribute> attsno =new ArrayList<ConfigAttribute>(); ConfigAttribute cano = new SecurityConfig("ROLE_NO"); attsno.add(cano); resourceMap.put("/other.jsp", attsno); } */ //参数是要访问的url,返回这个url对于的所有权限(或角色) public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException { // 将参数转为url String url = ((FilterInvocation)object).getRequestUrl(); //查询所有的url和角色的对应关系 if(rus == null){ rus = roleUrlDao.findAll(); } //匹配所有的url,并对角色去重 Set<String> roles = new HashSet<String>(); for(RoleUrlResource ru : rus){ if (urlMatcher.pathMatchesUrl(ru.getUrlResource().getUrl(), url)) { roles.add(ru.getRole().getRoleName()); } } Collection<ConfigAttribute> cas = new ArrayList<ConfigAttribute>(); for(String role : roles){ ConfigAttribute ca = new SecurityConfig(role); cas.add(ca); } return cas; /*Iterator<String> ite = resourceMap.keySet().iterator(); while (ite.hasNext()) { String resURL = ite.next(); if (urlMatcher.pathMatchesUrl(resURL, url)) { return resourceMap.get(resURL); } } return null; */ } public boolean supports(Class<?>clazz) { return true; } public Collection<ConfigAttribute> getAllConfigAttributes() { return null; } }
以上代码,在getAttributes方法中缓存起所有的对应关系(可以使用依赖注入了),并匹配所有 url ,对角色进行去重(因为多个url可能有重复的角色),这样就能修复那个bug了。
<?xml version="1.0" encoding="UTF-8"?> <b:beans xmlns="http://www.springframework.org/schema/security" xmlns:b="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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.1.xsd"> <!-- 配置不需要安全管理的界面 --> <http pattern="/jsp/css/**" security="none"></http> <http pattern="/jsp/js/**" security="none"></http> <http pattern="/jsp/images/**" security="none"></http> <http pattern="/login.jsp" security="none" /> <http pattern="/accessDenied.jsp" security="none" /> <http pattern="/index.jsp" security="none" /> <http use-expressions='true' entry-point-ref="myAuthenticationEntryPoint" access-denied-page="/accessDenied.jsp"> <!-- 使用自己自定义的登陆认证过滤器 --><!-- 这里一定要注释掉,因为我们需要重写它的过滤器 --> <!-- <form-login login-page="/login.jsp" authentication-failure-url="/accessDenied.jsp" default-target-url="/index.jsp" /> --> <!--访问/admin.jsp资源的用户必须具有ROLE_ADMIN的权限 --> <!-- <intercept-url pattern="/admin.jsp" access="ROLE_ADMIN" /> --> <!--访问/**资源的用户必须具有ROLE_USER的权限 --> <!-- <intercept-url pattern="/**" access="ROLE_USER" /> --> <session-management> <concurrency-control max-sessions="1" error-if-maximum-exceeded="false" /> </session-management> <!-- 认证和授权 --><!-- 重写登陆认证的过滤器,使我们可以拿到任何参数 --> <custom-filter ref="myAuthenticationFilter" position="FORM_LOGIN_FILTER" /> <custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR" /> <!-- 登出管理 --> <logout invalidate-session="true" logout-url="/j_spring_security_logout" /> </http> <!-- 未登录的切入点 --><!-- 需要有个切入点 --> <b:bean id="myAuthenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"> <b:property name="loginFormUrl" value="/login.jsp"></b:property> </b:bean> <!-- 登录验证器:用户有没有登录的资格 --><!-- 这个就是重写的认证过滤器 --> <b:bean id="myAuthenticationFilter" class="com.lcy.springSecurity.MyAuthenticationFilter"> <b:property name="authenticationManager" ref="authenticationManager" /> <b:property name="filterProcessesUrl" value="/j_spring_security_check" /> <b:property name="authenticationSuccessHandler"> <b:bean class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler"> <b:property name="defaultTargetUrl" value="/index.jsp" /> </b:bean> </b:property> <b:property name="authenticationFailureHandler"> <b:bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"> <b:property name="defaultFailureUrl" value="/accessDenied.jsp" /> </b:bean> </b:property> </b:bean> <!--一个自定义的filter,必须包含 authenticationManager,accessDecisionManager,securityMetadataSource三个属性,我们的所有控制将在这三个类中实现,解释详见具体配置 --> <b:bean id="myFilter" class="com.lcy.springSecurity.MyFilterSecurityInterceptor"> <b:property name="authenticationManager" ref="authenticationManager" /> <b:property name="accessDecisionManager" ref="myAccessDecisionManagerBean" /> <b:property name="securityMetadataSource" ref="securityMetadataSource" /> </b:bean> <!--验证配置,认证管理器,实现用户认证的入口,主要实现UserDetailsService接口即可 --> <authentication-manager alias="authenticationManager"> <authentication-provider user-service-ref="myUserDetailService"> <!--如果用户的密码采用加密的话 <password-encoder hash="md5" /> --> <!-- <password-encoder hash="md5" /> --> </authentication-provider> </authentication-manager> <!--在这个类中,你就可以从数据库中读入用户的密码,角色信息,是否锁定,账号是否过期等 --> <b:bean id="myUserDetailService" class="com.lcy.springSecurity.MyUserDetailService" /> <!--访问决策器,决定某个用户具有的角色,是否有足够的权限去访问某个资源 --> <b:bean id="myAccessDecisionManagerBean" class="com.lcy.springSecurity.MyAccessDecisionManager"> </b:bean> <!--资源源数据定义,将所有的资源和权限对应关系建立起来,即定义某一资源可以被哪些角色访问 --> <b:bean id="securityMetadataSource" class="com.lcy.springSecurity.MyInvocationSecurityMetadataSource" /> </b:beans>
我现在的项目需要的是,角色只要管理员、教师、学生,所以MyAuthenticationFilter(重写的认证过滤器):
package com.lcy.springSecurity; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import com.lcy.dao.IAdminDao; import com.lcy.dao.IStudentDao; import com.lcy.dao.ITeacherDao; import com.lcy.entity.Admin; import com.lcy.entity.Student; import com.lcy.entity.Teacher; public class MyAuthenticationFilter extends UsernamePasswordAuthenticationFilter { private static final String USERNAME = "username"; private static final String PASSWORD = "password"; @Resource private IStudentDao studentdao; @Resource private ITeacherDao teacherdao; @Resource private IAdminDao admindao; @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (!request.getMethod().equals("POST")) { throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); } String username = obtainUsername(request); String password = obtainPassword(request); String roletype = request.getParameter("roletype"); username = username.trim(); UsernamePasswordAuthenticationToken authRequest = null; if(!"".equals(roletype) || roletype != null){ if("student".equals(roletype)){ Student stu = studentdao.findById(username); //通过session把用户对象设置到session中 request.getSession().setAttribute("session_user", stu); //将角色标志在username上 username = "stu"+username; try { if (stu == null || !stu.getPassword().equals(password)) { BadCredentialsException exception = new BadCredentialsException("用户名或密码不匹配"); throw exception; } } catch (Exception e) { BadCredentialsException exception = new BadCredentialsException("没有此用户"); throw exception; } }else if("teacher".equals(roletype)){ Teacher tea = teacherdao.findById(username); //通过session把用户对象设置到session中 request.getSession().setAttribute("session_user", tea); //将角色标志在username上 username = "tea"+username; try { if (tea == null || !tea.getPassword().equals(password)) { BadCredentialsException exception = new BadCredentialsException("用户名或密码不匹配"); throw exception; } } catch (Exception e) { BadCredentialsException exception = new BadCredentialsException("没有此用户"); throw exception; } }else if("admin".equals(roletype)){ Admin adm = admindao.findById(username); //通过session把用户对象设置到session中 request.getSession().setAttribute("session_user", adm); //将角色标志在username上 username = "adm"+username; try { if (adm == null || !password.equals(adm.getPassword())) { BadCredentialsException exception = new BadCredentialsException("用户名或密码不匹配"); throw exception; } } catch (Exception e) { BadCredentialsException exception = new BadCredentialsException("没有此用户"); throw exception; } }else{ BadCredentialsException exception = new BadCredentialsException("系统错误:没有对应的角色!"); throw exception; } } //实现验证 authRequest = new UsernamePasswordAuthenticationToken(username, password); //允许设置用户详细属性 setDetails(request, authRequest); //运行 return this.getAuthenticationManager().authenticate(authRequest); } @Override protected String obtainUsername(HttpServletRequest request) { Object obj = request.getParameter(USERNAME); return null == obj ? "" : obj.toString(); } @Override protected String obtainPassword(HttpServletRequest request) { Object obj = request.getParameter(PASSWORD); return null == obj ? "" : obj.toString(); } @Override protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) { super.setDetails(request, authRequest); } }
MyUserDetailService:
package com.lcy.springSecurity; import java.util.ArrayList; import java.util.Collection; import javax.annotation.Resource; import org.springframework.dao.DataAccessException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import com.lcy.dao.IAdminDao; import com.lcy.dao.IStudentDao; import com.lcy.dao.ITeacherDao; import com.lcy.entity.Admin; import com.lcy.entity.Student; import com.lcy.entity.Teacher; public class MyUserDetailService implements UserDetailsService { @Resource private IStudentDao studentdao; @Resource private ITeacherDao teacherdao; @Resource private IAdminDao admindao; //登陆验证时,通过username获取用户的所有权限信息, //并返回User放到spring的全局缓存SecurityContextHolder中,以供授权器使用 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { Collection<GrantedAuthority> auths= new ArrayList<GrantedAuthority>(); //获取角色标志 String roletype = username.substring(0,3); username = username.substring(3); String password = ""; if("stu".equals(roletype)){ Student stu = studentdao.findById(username); password = stu.getPassword(); auths.add(new SimpleGrantedAuthority("ROLE_STU")); }else if("tea".equals(roletype)){ Teacher tea = teacherdao.findById(username); password = tea.getPassword(); auths.add(new SimpleGrantedAuthority("ROLE_TEA")); }else if("adm".equals(roletype)){ Admin adm = admindao.findById(username); password = adm.getPassword(); auths.add(new SimpleGrantedAuthority("ROLE_ADM")); } User user = new User(username, password, true, true, true, true, auths); return user; } }
本文来自博客园,作者:King-DA,转载请注明原文链接:https://www.cnblogs.com/qingmuchuanqi48/p/12694817.html