Spring源代码解析(十):Spring Acegi框架授权的实现

3 篇文章 0 订阅
Java代码

1.  //这里是拦截器拦截HTTP请求的入口

2.  publicvoid doFilter(ServletRequest request,ServletResponse response, FilterChain chain)

3.  throws IOException, ServletException {

4.  FilterInvocation fi = new FilterInvocation(request, response,chain);

5.  invoke(fi);

6.  }

7.  //这是具体的拦截调用

8.  publicvoid invoke(FilterInvocation fi) throws IOException, ServletException {

9.  if ((fi.getRequest() != null) &&(fi.getRequest().getAttribute(FILTER_APPLIED) != null)

10. && observeOncePerRequest) {

11. //在第一次进行过安全检查之后就不会再做了

12. fi.getChain().doFilter(fi.getRequest(),fi.getResponse());

13. } else {

14. //这是第一次收到相应的请求,需要做安全检测,同时把标志为设置好 - FILTER_APPLIED,下次就再有请求就不会作相同的安全检查了

15. if (fi.getRequest() != null) {

16. fi.getRequest().setAttribute(FILTER_APPLIED,Boolean.TRUE);

17. }

18. //这里是做安全检查的地方

19. InterceptorStatusToken token = super.beforeInvocation(fi);

20. //接着向拦截器链执行

21. try {

22. fi.getChain().doFilter(fi.getRequest(),fi.getResponse());

23. } finally {

24. super.afterInvocation(token, null);

25. }

26. }

27. }

Java代码

1.  //这里是拦截器拦截HTTP请求的入口

2.  publicvoid doFilter(ServletRequest request,ServletResponse response, FilterChain chain)

3.  throws IOException, ServletException {

4.  FilterInvocation fi = new FilterInvocation(request, response,chain);

5.  invoke(fi);

6.  }

7.  //这是具体的拦截调用

8.  publicvoid invoke(FilterInvocation fi) throws IOException, ServletException {

9.  if ((fi.getRequest() != null) &&(fi.getRequest().getAttribute(FILTER_APPLIED) != null)

10. && observeOncePerRequest) {

11. //在第一次进行过安全检查之后就不会再做了

12. fi.getChain().doFilter(fi.getRequest(),fi.getResponse());

13. } else {

14. //这是第一次收到相应的请求,需要做安全检测,同时把标志为设置好 - FILTER_APPLIED,下次就再有请求就不会作相同的安全检查了

15. if (fi.getRequest() != null) {

16. fi.getRequest().setAttribute(FILTER_APPLIED,Boolean.TRUE);

17. }

18. //这里是做安全检查的地方

19. InterceptorStatusToken token = super.beforeInvocation(fi);

20. //接着向拦截器链执行

21. try {

22. fi.getChain().doFilter(fi.getRequest(),fi.getResponse());

23. } finally {

24. super.afterInvocation(token, null);

25. }

26. }

27. }


我们看看在AbstractSecurityInterceptor是怎样对HTTP请求作安全检测的:

Java代码

1.  protected InterceptorStatusTokenbeforeInvocation(Object object) {

2.  Assert.notNull(object, "Object was null");

3.   

4.  if(!getSecureObjectClass().isAssignableFrom(object.getClass())) {

5.  thrownew IllegalArgumentException("Security invocation attempted forobject "

6.  + object.getClass().getName()

7.  + " but AbstractSecurityInterceptor onlyconfigured to support secure objects of type: "

8.  + getSecureObjectClass());

9.  }

10. //这里读取配置FilterSecurityInterceptorObjectDefinitionSource属性,这些属性配置了资源的安全设置

11. ConfigAttributeDefinition attr = this.obtainObjectDefinitionSource().getAttributes(object);

12.  

13. if (attr == null) {

14. if(rejectPublicInvocations) {

15. thrownew IllegalArgumentException(

16. "No public invocations are allowed viathis AbstractSecurityInterceptor. "

17. + "This indicates a configuration errorbecause the "

18. + "AbstractSecurityInterceptor.rejectPublicInvocationsproperty is set to 'true'");

19. }

20.  

21. if (logger.isDebugEnabled()) {

22. logger.debug("Public object - authentication notattempted");

23. }

24.  

25. publishEvent(new PublicInvocationEvent(object));

26.  

27. returnnull; // no further work post-invocation

28. }

29.  

30.  

31. if (logger.isDebugEnabled()) {

32. logger.debug("Secure object: " + object.toString() + "; ConfigAttributes: " + attr.toString());

33. }

34. //这里从SecurityContextHolder中去取Authentication对象,一般在登录时会放到SecurityContextHolder中去

35. if(SecurityContextHolder.getContext().getAuthentication() == null) {

36. credentialsNotFound(messages.getMessage("AbstractSecurityInterceptor.authenticationNotFound",

37. "An Authentication object was notfound in the SecurityContext"), object, attr);

38. }

39.  

40. // 如果前面没有处理鉴权,这里需要对鉴权进行处理

41. Authentication authenticated;

42.  

43. if(!SecurityContextHolder.getContext().getAuthentication().isAuthenticated() ||alwaysReauthenticate) {

44. try {//调用配置好的AuthenticationManager处理鉴权,如果鉴权不成功,抛出异常结束处理

45. authenticated = this.authenticationManager.authenticate(SecurityContextHolder.getContext()

46. .getAuthentication());

47. } catch (AuthenticationExceptionauthenticationException) {

48. throw authenticationException;

49. }

50.  

51. // We don'tauthenticated.setAuthentication(true), because each provider should do that

52. if (logger.isDebugEnabled()) {

53. logger.debug("Successfully Authenticated: " + authenticated.toString());

54. }

55. //这里把鉴权成功后得到的Authentication保存到SecurityContextHolder中供下次使用

56. SecurityContextHolder.getContext().setAuthentication(authenticated);

57. } else {//这里处理前面已经通过鉴权的请求,先从SecurityContextHolder中去取得Authentication

58. authenticated =SecurityContextHolder.getContext().getAuthentication();

59.  

60. if (logger.isDebugEnabled()) {

61. logger.debug("Previously Authenticated: " + authenticated.toString());

62. }

63. }

64.  

65. // 这是处理授权的过程

66. try {

67. //调用配置好的AccessDecisionManager来进行授权

68. this.accessDecisionManager.decide(authenticated,object, attr);

69. } catch (AccessDeniedExceptionaccessDeniedException) {

70. //授权不成功向外发布事件

71. AuthorizationFailureEvent event = new AuthorizationFailureEvent(object, attr,authenticated,

72. accessDeniedException);

73. publishEvent(event);

74.  

75. throw accessDeniedException;

76. }

77.  

78. if (logger.isDebugEnabled()) {

79. logger.debug("Authorization successful");

80. }

81.  

82. AuthorizedEvent event = new AuthorizedEvent(object, attr,authenticated);

83. publishEvent(event);

84.  

85. // 这里构建一个RunAsManager来替代当前的Authentication对象,默认情况下使用的是NullRunAsManager会把SecurityContextHolder中的Authentication对象清空

86. Authentication runAs = this.runAsManager.buildRunAs(authenticated,object, attr);

87.  

88. if (runAs == null) {

89. if (logger.isDebugEnabled()) {

90. logger.debug("RunAsManager did not changeAuthentication object");

91. }

92.  

93. // no further work post-invocation

94. returnnew InterceptorStatusToken(authenticated, false, attr, object);

95. } else {

96. if (logger.isDebugEnabled()) {

97. logger.debug("Switching to RunAs Authentication:" +runAs.toString());

98. }

99.  

100.     SecurityContextHolder.getContext().setAuthentication(runAs);

101.      

102.     // revert to token.Authenticatedpost-invocation

103.     returnnew InterceptorStatusToken(authenticated, true, attr, object);

104.     }

105.     }

Java代码

1.  protected InterceptorStatusTokenbeforeInvocation(Object object) {

2.  Assert.notNull(object, "Object was null");

3.   

4.  if(!getSecureObjectClass().isAssignableFrom(object.getClass())) {

5.  thrownew IllegalArgumentException("Security invocation attempted forobject "

6.  + object.getClass().getName()

7.  + " but AbstractSecurityInterceptor onlyconfigured to support secure objects of type: "

8.  + getSecureObjectClass());

9.  }

10. //这里读取配置FilterSecurityInterceptorObjectDefinitionSource属性,这些属性配置了资源的安全设置

11. ConfigAttributeDefinition attr = this.obtainObjectDefinitionSource().getAttributes(object);

12.  

13. if (attr == null) {

14. if(rejectPublicInvocations) {

15. thrownew IllegalArgumentException(

16. "No public invocations are allowed viathis AbstractSecurityInterceptor. "

17. + "This indicates a configuration errorbecause the "

18. + "AbstractSecurityInterceptor.rejectPublicInvocationsproperty is set to 'true'");

19. }

20.  

21. if (logger.isDebugEnabled()) {

22. logger.debug("Public object - authentication notattempted");

23. }

24.  

25. publishEvent(new PublicInvocationEvent(object));

26.  

27. returnnull; // no further work post-invocation

28. }

29.  

30.  

31. if (logger.isDebugEnabled()) {

32. logger.debug("Secure object: " + object.toString() + "; ConfigAttributes: " + attr.toString());

33. }

34. //这里从SecurityContextHolder中去取Authentication对象,一般在登录时会放到SecurityContextHolder中去

35. if (SecurityContextHolder.getContext().getAuthentication()== null) {

36. credentialsNotFound(messages.getMessage("AbstractSecurityInterceptor.authenticationNotFound",

37. "An Authentication object was notfound in the SecurityContext"), object, attr);

38. }

39.  

40. // 如果前面没有处理鉴权,这里需要对鉴权进行处理

41. Authentication authenticated;

42.  

43. if(!SecurityContextHolder.getContext().getAuthentication().isAuthenticated() ||alwaysReauthenticate) {

44. try {//调用配置好的AuthenticationManager处理鉴权,如果鉴权不成功,抛出异常结束处理

45. authenticated = this.authenticationManager.authenticate(SecurityContextHolder.getContext()

46. .getAuthentication());

47. } catch (AuthenticationExceptionauthenticationException) {

48. throw authenticationException;

49. }

50.  

51. // We don'tauthenticated.setAuthentication(true), because each provider should do that

52. if (logger.isDebugEnabled()) {

53. logger.debug("Successfully Authenticated: " + authenticated.toString());

54. }

55. //这里把鉴权成功后得到的Authentication保存到SecurityContextHolder中供下次使用

56. SecurityContextHolder.getContext().setAuthentication(authenticated);

57. } else {//这里处理前面已经通过鉴权的请求,先从SecurityContextHolder中去取得Authentication

58. authenticated =SecurityContextHolder.getContext().getAuthentication();

59.  

60. if (logger.isDebugEnabled()) {

61. logger.debug("Previously Authenticated: " + authenticated.toString());

62. }

63. }

64.  

65. // 这是处理授权的过程

66. try {

67. //调用配置好的AccessDecisionManager来进行授权

68. this.accessDecisionManager.decide(authenticated,object, attr);

69. } catch (AccessDeniedExceptionaccessDeniedException) {

70. //授权不成功向外发布事件

71. AuthorizationFailureEvent event = new AuthorizationFailureEvent(object, attr,authenticated,

72. accessDeniedException);

73. publishEvent(event);

74.  

75. throw accessDeniedException;

76. }

77.  

78. if (logger.isDebugEnabled()) {

79. logger.debug("Authorization successful");

80. }

81.  

82. AuthorizedEvent event = new AuthorizedEvent(object, attr,authenticated);

83. publishEvent(event);

84.  

85. // 这里构建一个RunAsManager来替代当前的Authentication对象,默认情况下使用的是NullRunAsManager会把SecurityContextHolder中的Authentication对象清空

86. Authentication runAs = this.runAsManager.buildRunAs(authenticated,object, attr);

87.  

88. if (runAs == null) {

89. if (logger.isDebugEnabled()) {

90. logger.debug("RunAsManager did not changeAuthentication object");

91. }

92.  

93. // no further work post-invocation

94. returnnew InterceptorStatusToken(authenticated, false, attr, object);

95. } else {

96. if (logger.isDebugEnabled()) {

97. logger.debug("Switching to RunAs Authentication:" +runAs.toString());

98. }

99.  

100.     SecurityContextHolder.getContext().setAuthentication(runAs);

101.      

102.     // revert to token.Authenticatedpost-invocation

103.     returnnew InterceptorStatusToken(authenticated, true, attr, object);

104.     }

105.     }


到这里我们假设配置AffirmativeBased作为AccessDecisionManager

Java代码

1.  //这里定义了决策机制,需要全票才能通过

2.  publicvoid decide(Authentication authentication,Object object, ConfigAttributeDefinition config)

3.  throws AccessDeniedException {

4.  //这里取得配置好的迭代器集合

5.  Iterator iter = this.getDecisionVoters().iterator();

6.  int deny = 0;

7.  //依次使用各个投票器进行投票,并对投票结果进行计票

8.  while (iter.hasNext()) {

9.  AccessDecisionVoter voter =(AccessDecisionVoter) iter.next();

10. int result = voter.vote(authentication,object, config);

11. //这是对投票结果进行处理,如果遇到其中一票通过,那就授权通过,如果是弃权或者反对,那就继续投票

12. switch (result) {

13. case AccessDecisionVoter.ACCESS_GRANTED:

14. return;

15.  

16. case AccessDecisionVoter.ACCESS_DENIED:

17. //这里对反对票进行计数

18. deny++;

19.  

20. break;

21.  

22. default:

23. break;

24. }

25. }

26. //如果有反对票,抛出异常,整个授权不通过

27. if (deny > 0) {

28. thrownewAccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied",

29. "Access is denied"));

30. }

31.  

32. // 这里对弃权票进行处理,看看是全是弃权票的决定情况,默认是不通过,由allowIfAllAbstainDecisions变量控制

33. checkAllowIfAllAbstainDecisions();

34. }

35. 具体的投票由投票器进行,我们这里配置了RoleVoter来进行投票:

36. publicint vote(Authentication authentication,Object object, ConfigAttributeDefinition config) {

37. int result = ACCESS_ABSTAIN;

38. //这里取得资源的安全配置

39. Iterator iter =config.getConfigAttributes();

40.  

41. while (iter.hasNext()) {

42. ConfigAttribute attribute = (ConfigAttribute)iter.next();

43.  

44. if (this.supports(attribute)) {

45. result = ACCESS_DENIED;

46.  

47. // 这里对资源配置的安全授权级别进行判断,也就是匹配ROLE为前缀的角色配置

48. // 遍历每个配置属性,如果其中一个匹配该主体持有的GrantedAuthority,则访问被允许。

49. for (int i = 0; i <authentication.getAuthorities().length; i++) {

50. if(attribute.getAttribute().equals(authentication.getAuthorities()[i].getAuthority())){

51. return ACCESS_GRANTED;

52. }

53. }

54. }

55. }

56.  

57. return result;

58. }

Java代码

1.  //这里定义了决策机制,需要全票才能通过

2.  publicvoid decide(Authentication authentication,Object object, ConfigAttributeDefinition config)

3.  throws AccessDeniedException {

4.  //这里取得配置好的迭代器集合

5.  Iterator iter = this.getDecisionVoters().iterator();

6.  int deny = 0;

7.  //依次使用各个投票器进行投票,并对投票结果进行计票

8.  while (iter.hasNext()) {

9.  AccessDecisionVoter voter =(AccessDecisionVoter) iter.next();

10. int result = voter.vote(authentication,object, config);

11. //这是对投票结果进行处理,如果遇到其中一票通过,那就授权通过,如果是弃权或者反对,那就继续投票

12. switch (result) {

13. case AccessDecisionVoter.ACCESS_GRANTED:

14. return;

15.  

16. case AccessDecisionVoter.ACCESS_DENIED:

17. //这里对反对票进行计数

18. deny++;

19.  

20. break;

21.  

22. default:

23. break;

24. }

25. }

26. //如果有反对票,抛出异常,整个授权不通过

27. if (deny > 0) {

28. thrownewAccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied",

29. "Access is denied"));

30. }

31.  

32. // 这里对弃权票进行处理,看看是全是弃权票的决定情况,默认是不通过,由allowIfAllAbstainDecisions变量控制

33. checkAllowIfAllAbstainDecisions();

34. }

35. 具体的投票由投票器进行,我们这里配置了RoleVoter来进行投票:

36. publicint vote(Authentication authentication,Object object, ConfigAttributeDefinition config) {

37. int result = ACCESS_ABSTAIN;

38. //这里取得资源的安全配置

39. Iterator iter =config.getConfigAttributes();

40.  

41. while (iter.hasNext()) {

42. ConfigAttribute attribute =(ConfigAttribute) iter.next();

43.  

44. if (this.supports(attribute)) {

45. result = ACCESS_DENIED;

46.  

47. // 这里对资源配置的安全授权级别进行判断,也就是匹配ROLE为前缀的角色配置

48. // 遍历每个配置属性,如果其中一个匹配该主体持有的GrantedAuthority,则访问被允许。

49. for (int i = 0; i <authentication.getAuthorities().length; i++) {

50. if(attribute.getAttribute().equals(authentication.getAuthorities()[i].getAuthority())){

51. return ACCESS_GRANTED;

52. }

53. }

54. }

55. }

56.  

57. return result;

58. }


上面就是对整个授权过程的一个分析,从FilterSecurityInterceptor拦截Http请求入手,然后读取对资源的安全配置以后,把这些信息交由AccessDecisionManager来进行决策,Spring为我们提供了若干决策器来使用,在决策器中我们可以配置投票器来完成投票,我们在上面具体分析了角色投票器的使用过程。

 

 

看源代码学习Session的内容是如何存储的?

org.apache.catalina.session.StandardSession
使用如下的结构来存储session的值

protected Map attributes = newConcurrentHashMap();


public void setAttribute(String name, Object value)
里,实际调用了
setAttribute(name,value,true);


public void setAttribute(String name, Object value, boolean notify)

里,如果value0,则调用removeAttrbute方法,将属性移除

if (value == null) {
removeAttribute(name);
return;
}

否则调用

Object unbound =attributes.put(name, value);
将数值保存到里面,同时拿到以前的值

我们来看看
public void removeAttribute(String name, boolean notify)

调用了
protected void removeAttributeInternal(String name, boolean notify)

// Avoid NPE =NullPointerException 呵呵,就是空指针
if (name == null) return;

// Remove this attribute fromour collection
//
就是简单的从Map里面删除
Object value = attributes.remove(name);

// 后面还有一些事件通知的方法调用

可见在Session里,我们常用的操作就是这么实现的,没有什么高深的东西。
只要我们能拿到属于我们的session对象,就可以拿到我们保存在里面的东西了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值