Spring security登录原理
来源:互联网 发布:mac右上角图标管理 编辑:程序博客网 时间:2024/04/29 20:18
是UBA项目中的spring security登录原理
web应用启动,初始化
会初始化spring security的拦截器(好像也是职责链模式),在web.xml中:
<filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class></filter>
同时会实例化全部spring容器管理的bean,包括:
<bean id="filterSecurityInterceptor" class="org.springframework.security.intercept.web.FilterSecurityInterceptor"> <s:custom-filter before="FILTER_SECURITY_INTERCEPTOR" /> <property name="accessDecisionManager" ref="accessDecisionManager" /> <property name="objectDefinitionSource" ref="databaseDefinitionSource" /></bean> <!-- DefinitionSource工厂,使用resourceDetailsService提供的URL-授权关系. --><bean id="databaseDefinitionSource" class="org.springside.modules.security.springsecurity.DefinitionSourceFactoryBean"> <property name="resourceDetailsService" ref="resourceDetailsService" /></bean><!-- 项目实现的URL-授权查询服务 --><bean id="resourceDetailsService" class="com.ebupt.UBA.service.security.ResourceDetailsServiceImpl" /><!-- 授权判断配置, 将授权名称的默认前缀由ROLE_改为A_.--><bean id="accessDecisionManager" class="org.springframework.security.vote.AffirmativeBased"> <property name="decisionVoters"> <list> <bean class="org.springframework.security.vote.RoleVoter"> <property name="rolePrefix" value="A_" /> </bean> <bean class="org.springframework.security.vote.AuthenticatedVoter" /> </list> </property></bean>
在resourceDetailsService类中会读取全部的resource-authority映射map信息(用于之后查询用户是否有权限):
/** * 从数据库查询URL--权限定义Map的实现类. * */@Transactional(readOnly = true)public class ResourceDetailsServiceImpl implements ResourceDetailsService { @Autowired private SecurityManager securityManager; /** * @see ResourceDetailsService#getRequestMap() */ public LinkedHashMap<String, String> getRequestMap() throws Exception { List<Resource> resourceList = securityManager.getUrlResourceWithAuthorities(); LinkedHashMap<String, String> requestMap = new LinkedHashMap<String, String>(resourceList.size()); for (Resource resource : resourceList) { requestMap.put(resource.getValue(), resource.getAuthNames()); } return requestMap; }}
输入localhost:8080/UBA
web应用默认主页是index.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="org.springside.modules.security.springsecurity.SpringSecurityUtils"%><%@include file="/common/taglibs.jsp"%><% request.setAttribute("loginName",SpringSecurityUtils.getCurrentUserName());%><c:if test="${loginName == 'roleAnonymous'}"><jsp:forward page="/common/login.jsp"/></c:if><c:if test="${loginName != 'roleAnonymous'}"><jsp:forward page="/homepage/home-page.action"/></c:if>
看到这个默认页面导入了spring security的包
利用SpringSecurityUtils.getCurrentUserName()获取spring 容器中的UserName(当然一开始是没有登录的)。
如果UserName有效,那么跳转home-page.action
如果UserName无效,那么跳转login.jsp
login,跳转到login.jsp
这个是登录页面:
login.jsp主要是做很多校验工作,核心代码还是发送登录请求:
<form id="my_form" action="${ctx}/j_spring_security_check" method="post"><input type="text" value="" id="loginName" name="j_username" style="width:185px;height:18px;border:0px;"/><input type="password" value="" id="password" name="j_password" style="width:185px;height:16px;border:0px;"/><input type="text" value="" id="captcha" name="j_captcha" style="width:89px;height:15px;margin-top:2px;border:0px;"/></form>
发送请求给j_spring_security_check
。
参数有j_username,j_password,j_captcha
,这几个参数名字应该是不能变的,因为要调用spring security的验证。
spring根据输入的用户名获取用户信息
j_spring_security_check这个是spring security里面的约定。
applicationContext-security.xml中有
<!-- 认证配置 --> <s:authentication-provider user-service-ref="userDetailsService"> <!-- 可设置hash使用sha1或md5散列密码后再存入数据库 --> <s:password-encoder hash="md5" /> </s:authentication-provider> <bean id="userDetailsService" class="com.ebupt.UBA.service.security.UserDetailsServiceImpl" />
之后会回调UserDetailsServiceImpl的loadUserByUsername方法,
其中:
@Transactional(readOnly = true)public class UserDetailsServiceImpl implements UserDetailsService { @Autowired private SecurityManager securityManager; /** * 获取用户Details信息的回调函数. */ public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException, DataAccessException { String username; if(userName.indexOf("re_")==0){ username=userName.replace("re_", ""); }else{ username=userName; } User user = securityManager.findUserByLoginName(username); if (user == null) throw new UsernameNotFoundException("用户" + username + " 不存在"); GrantedAuthority[] grantedAuths = obtainGrantedAuthorities(user); // mras_d中无以下属性,暂时全部设为true. boolean enabled = true; boolean accountNonExpired = true; boolean credentialsNonExpired = true; boolean accountNonLocked = true; String pwd=user.getPassword(); if(userName.indexOf("re_")==0){ Md5PasswordEncoder md = new Md5PasswordEncoder(); System.out.println( md.encodePassword("1qaz2wsx",null)); pwd=md.encodePassword(pwd,null); } org.springframework.security.userdetails.User userdetail = new org.springframework.security.userdetails.User( user.getLoginName(), pwd, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, grantedAuths); return userdetail; } /** * 获得用户所有角色的权限集合. */ private GrantedAuthority[] obtainGrantedAuthorities(User user) { Set<GrantedAuthority> authSet = new HashSet<GrantedAuthority>(); for (Role role : user.getRoles()) { for (Authority authority : role.getAuthorities()) { authSet.add(new GrantedAuthorityImpl(authority.getName())); } } return authSet.toArray(new GrantedAuthority[authSet.size()]); }}
这里根据用户的名字获取了用户密码等信息,new 了一个User类返回,中间存放了若干信息:用户名,密码,还有用户的全部权限名字。
new org.springframework.security.userdetails.User( user.getLoginName(), pwd, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, grantedAuths);
然后我理解的是spring security自己会比对用户的密码,如果正确,那么就会跳转至登录前的拦截页面(一开始的拦截页面应该是index.jsp,也就是home-page.action,其他的拦截页面就是在UBA_RESOURCE中的页面,之前输入的是啥就是啥)。
没有登录或者已经登录的情况下输入某个url
应该是被spring security的拦截器拦截了,我理解是DelegatingFilterProxy 。
拦截后根据容器中一开始查询出的资源权限映射关系,查询该url所需要的权限,和用户全部的权限进行比对。
如果用户满足了这些权限,跳转到该页面
如果用户没有满足这些权限,跳转到登录页面(这里做的有问题,因为UBA这个项目比较简单,一般是一个用户有超级权限,其他人都用这个用户来登。如果是多个用户有不同权限时,应该是跳转到”您没有权限“页面)。
spring security里的配置还是不太懂(还要琢磨琢磨):
<s:http auto-config="true" access-decision-manager-ref="accessDecisionManager"> <s:intercept-url pattern="/common/login.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY" /> <s:form-login login-page="/common/login.jsp" default-target-url="/" authentication-failure-url="/common/login.jsp?error=true" /> <s:logout logout-success-url="/common/login.jsp" /> <s:remember-me /> <!-- key="e37f4b31-0c45-11dd-bd0b-0800200c9a66"--> </s:http>
还有,用户在输入一个url的时候,如何判断这个url是一个资源?spring security默认url就是资源?还是要配置什么?
在spring security的拦截器拦截用户请求没有登录之后,就不会再走struts的拦截器了。
尝试在去掉web.xml中的springSecurityFilterChain后,用户可以不登录就进系统了。
在一个浏览器中登录后,这时用另外一个浏览器再进系统,需要登录吗?
试过是需要的,因为http request默认会带上session Id(如果有的话),所以spring security的实现其实是通过session Id 来获取出之前web 容器中的User实例的。
所以在web容器中可能有多个实例,如果是不同用户登录的话。
未完成
1、尝试在项目中修改数据库,配置用户的权限,尝试有不同用户不同权限登录场景。
2、自己手写一个分布式web应用,使用spring security实现登录效果。
参考
Spring Security原理及教程
- Spring security登录原理
- spring security 登录验证
- spring Security 登录验证
- spring security手动登录
- Spring security注销登录
- spring security登录验证
- Spring security框架原理
- Spring Security 原理
- Spring Security 3.1自定义登录
- spring security +cas单点登录
- Spring-security不能重复登录
- Spring Security的登录过程
- Spring Security 3.1 登录验证
- spring security多入口登录
- 2. Spring Security 关于登录
- Spring Security-02-关于登录
- Spring Security 基础登录实例
- spring security 登录验证 感想
- Webrtc的iOS框架编译
- Android API,版本对照
- 通过网络远程控制ARM系统GPIO应用实例
- p2p打洞技术文章
- iOS之statusBar相关设置(UIStatusBar) 你看这里就足够了
- Spring security登录原理
- Hive连接MYSQL数据OK,查询出现in thread "Thread-18" java.lang.IllegalArgumentException:Does not contain a vali
- Oracle存储过程详解(五)-嵌套
- OS-->Git操作演练(项目实用命令)
- 支付系统各接口总结
- iOS 7 之后字体设置新方法
- Swift中Debug和Release两种状态下print()函数调试切换
- iOS获取时间戳
- EditText 监听内容变化