spring4 系列五 security 和sso

安全包括 验证身份和授权,spring对这2部分都进行了支持。

一、基本概念和javase抽象

subject = principal(身份) + credential(凭证)

pricipal的例子:身份证号、用户名、电话号码

credential的例子:密码、证书

Permission:权限

Policy:权限控制策略

AccessController:使用权限

ProtectionDomain:维护了一组身份和权限

加解密:

Cipher 加密服务

MessageDigest 摘要

SecretKey 对称秘钥

PublicKey和PrivateKey 非对称秘钥

KeySpec具体的秘钥的说明

Message Authentication Code (MAC):添加了秘钥的摘要算法

Certificate证书:由发证机构加密过的公钥

签名:(用私钥加密)

Signature signature = Signature.getInstance("SHA1withDSA");

signature.initSign(privateKey);

byte[] data = "Hello World".getBytes();

signature.update(data);

byte[] signatureData = signature.sign(); //得到签名

signature.initVerify(publicKey);

signature.update(data);

boolean result = signature.verify(signatureData); //进行验证

二、spring secure概览

1、基本概念:

UserDetails:安全相关的用户信息

GrantedAuthority[] getAuthorities():用户权限信息

UserDetailsService:loadUserByUsername

Authentication 代表一个和应用程序交互的待认证用户,内部使用UserDetails。

后面的访问控制基于这个类。pricipal + GrantedAuthority

SecurityContext 存储Authentication

SecurityContextHolder 框架层的入口

HttpSession->HttpSessionContextIntegrationFilter

->SecurityContextHolder->SecurityContext ->AuthenticationManager(验证)+AccessDecisionManager(访问控制)

DaoAuthenticationProvider-》UserDetailService

AuthenticationManager: AuthenticationProvider 授权信息注入context

AccessDecisionManager= AccessDecisionVoter(民主投票)

ExceptionTranslationFilter:权限不合适时的异常处理

AuthenticationEntryPoint:登陆入口

2、用户认证过程:

1.你点击一个链接访问一个网页; 

2.浏览器发送一个请求到服务器,服务器判断出你正在访问一个受保护的资源; 

3.如果此时你并未通过身份认证,服务器发回一个响应提示你进行认证——这个响应可能是一个HTTP响应代码,抑或重定向到一个指定页面; 

4.根据系统使用认证机制的不同,浏览器或者重定向到一个登录页面中,或者由浏览器通过一些其它的方式获取你的身份信息(如通过BASIC认证对话框、一 个Cookie或一个X509证书); 

5.浏览器再次将用户身份信息发送到服务器上(可能是一个用户登录表单的HTTP POST信息、也可能是包含认证信息的HTTP报文头); 

6.服务器判断用户认证信息是否有效,如果无效,一般情况下,浏览器会要求你继续尝试,这意味着返回第3步。如果有效,则到达下一步; 

7.服务器重新响应第2步所提交的原始请求,并判断该请求所访问的程序资源是否在你的权限范围内,如果你有权访问,请求将得到正确的执行并返回结果。否 则,你将收到一个HTTP 403错误,这意味着你被禁止访问。 

3、访问控制过程:

1. 从SecurityContext中取出已经认证过的Authentication(包括权限信息); 

2. 通过反射机制,根据目标安全对象和“配置属性”得到访问目标安全对象所需的权限; 

3. AccessDecisionManager根据Authentication的授权信息和目标安全对象所需权限做出是否有权访问的判断。如果无权访问,Acegi将抛出AccessDeniedException异常,否则到下一步; 

4. 访问安全对象并获取结果(返回值或HTTP响应); 

5.AbstractSecurityInterceptor可以在结果返回前进行处理:更改结果或抛出异常。   

三、spring相关jar概览

security-core 用户、token、session等的维护

UserDetailsService TokenService SessionRegistry AbstractAuthenticationToken

security-oauth2 对oauth2的支持

security-config 资源权限的配置

SecurityConfigurer HttpSecurityBuilder

security-web   使用filter等与容器相融合

DefaultRedirectStrategy DefaultSecurityFilterChain

oauth2基本过程:重定向到server、auth、访问token、身份数据插入Spring Security context

四、使用

1、依赖:

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-security</artifactId>

</dependency>

2、代码

@EnableWebSecurity  

默认配置

1、访问应用中的每个URL都需要进行验证

2、生成一个登陆表单

3、允许用户使用username和password来登陆

4、允许用户注销

5、CSRF攻击拦截

6、 Session Fixation攻击

7、 安全Header集成

extends WebSecurityConfigurerAdapter

@Bean

public UserDetailsService userDetailsService() {

    return new CustomUserDetailsService();

}

@Bean

public PasswordEncoder passwordEncoder(){

    return new Md5PasswordEncoder();

}

@Bean

public AuthenticationProvider authenticationProvider(){

    DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();

    authenticationProvider.setUserDetailsService(userDetailsService());

    authenticationProvider.setPasswordEncoder(passwordEncoder());

    return authenticationProvider;

}

protected void configure(AuthenticationManagerBuilder auth) throws Exception {

    //auth.userDetailsService(userDetailsService());

    auth.authenticationProvider(authenticationProvider());

}

protected void configure(HttpSecurity http) throws Exception {

http.antMatcher("/**"). 

// 根据request验证

authorizeRequests()

.antMatchers("/", "/login**", "/webjars/**")

.permitAll()

// 其他的 <intercept-url pattern="/**" access="authenticated"/>

.anyRequest()

.authenticated().and()

.exceptionHandling()

.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/")).and()

// 允许所有人logout

.logout().logoutSuccessUrl("/").permitAll().and()

// csrf支持

.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and()

// 注册sso的filter

.addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);

}

五、sso

<dependency>

<groupId>org.springframework.security.oauth</groupId>

<artifactId>spring-security-oauth2</artifactId>

</dependency>

addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);

security:

  oauth2:

    client:

      clientId: 233668646673605

      clientSecret: 33b17e044ee6a4fa383f46ec6e28ea1d

      accessTokenUri: https://graph.facebook.com/oauth/access_token

      userAuthorizationUri: https://www.facebook.com/dialog/oauth

      tokenName: oauth_token

      authenticationScheme: query

      clientAuthenticationScheme: form

    resource:

      userInfoUri: https://graph.facebook.com/me

六、内部实现细节

1、安全在web中使用filter,在app中使用aop,本质是在正常的请求前后加点料

2、@EnableWebSecurity 内部会注入一个springSecurityFilterChain

springSecurityFilterChain内部根据url来配置对应的filter

3、HttpSecurity用来 配置url、filter、对应的权限

4、AuthenticationManagerBuilder 配置验证的方式,比如UserDetailsService、passwordEncoder等

5、sso的实现:添加了一个filter OAuth2ClientAuthenticationProcessingFilter

6、OAuth2ClientAuthenticationProcessingFilter=AuthorizationCodeResourceDetails(获取token)+ResourceServerProperties(获取user信息)

七、附录

oauth2.0过程:

1》client app 向server请求临时令牌

2》获得后,带着临时token去server验证用户名、密码  # auth url

3》验证后server 回调client app获得授权

4》client app用临时token获得 acess token    # token url

5》用access token获取用户信息# user url

application.xml中的配置

userAuthorizationUri       auth url

accessTokenUri   token url

userInfoUri   user url

猜你喜欢

转载自eric-weitm.iteye.com/blog/2386620