oauth2整合security(密码模式)

oauth2 password 密码模式获取access_token流程

密码模式(Resource Owner Password Credentials Grant)中,用户向客户端提供自己的用户名和密码。客户端使用这些信息,向"服务商提供商"索要授权。
在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分,或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。

(A)用户向客户端提供用户名和密码。

(B)客户端将用户名和密码发给认证服务器,向后者请求令牌。 客户端发出的HTTP请求,包含以下参数:
grant_type:表示授权类型,此处的值固定为"password",必选项。
username:表示用户名,必选项。
password:表示用户的密码,必选项。
scope:表示权限范围,可选项。

(C)认证服务器确认无误后,向客户端提供访问令牌。

快速上手

redis 存储模式
pom

<dependencies>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
        dependency>

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-freemarkerartifactId>
        dependency>

        spring-boot 整合security -->
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-securityartifactId>
            <exclusions>
                
                <exclusion>
                    <artifactId>spring-security-oauth2artifactId>
                    <groupId>org.springframework.security.oauthgroupId>
                exclusion>
            exclusions>
        dependency>

        
        <dependency>
            <groupId>org.springframework.security.oauthgroupId>
            <artifactId>spring-security-oauth2artifactId>
            <version>2.3.3.RELEASEversion>
        dependency>


        <dependency>
            <groupId>io.jsonwebtokengroupId>
            <artifactId>jjwtartifactId>
            <version>0.6.0version>
        dependency>
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>fastjsonartifactId>
            <version>1.2.62version>
        dependency>
        <dependency>
            <groupId>org.apache.commonsgroupId>
            <artifactId>commons-lang3artifactId>
        dependency>

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-data-redisartifactId>
        dependency>
        <dependency>
            <groupId>org.apache.commonsgroupId>
            <artifactId>commons-pool2artifactId>
        dependency>

    dependencies>

security配置 配置登陆权限

@Component
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
     

    @Bean
    public PasswordEncoder passwordEncoder() {
     
        return new BCryptPasswordEncoder();
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
     
        http.formLogin().permitAll()
                .and().authorizeRequests()
                .antMatchers("/oauth/**").permitAll()
                .anyRequest().authenticated()
                .and().logout().permitAll()
                .and().csrf().disable();

    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
     
        return super.authenticationManagerBean();
    }

}

service 配置用户名密码

@Service
public class UserService implements UserDetailsService {
     

    @Autowired
    private PasswordEncoder passwordEncoder;

    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
     
        String password = passwordEncoder.encode("123456");
        return new User("admin", password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
    }
}

redis配置中心

@Configuration
public class RedisConfig {
     

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @Bean
    public TokenStore tokenStore() {
     
        return new RedisTokenStore(redisConnectionFactory);
    }
}

授权认证

/**
 * 认证授权Server端
 */
@Component
@EnableAuthorizationServer
public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter {
     
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AuthenticationManager authenticationManagerBean;
    @Autowired
    private UserService userService;
    @Autowired
    private TokenStore tokenStore;


    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
     
        endpoints.authenticationManager(authenticationManagerBean) //使用密码模式需要配置
                .reuseRefreshTokens(false)
                .tokenStore(tokenStore)
                .userDetailsService(userService)  //refresh_token是否重复使用
                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST); //支持GET,POST请求
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
     
        //允许表单提交
        security.allowFormAuthenticationForClients()
                .checkTokenAccess("permitAll()");
    }


    /**
     * appid mayikt secret= 123456
     *
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
     
        /**
         * 密码模式获取 token http://localhost:8080/oauth/token?username=admin&password=123456&grant_type=password&client_id=appId&client_secret=123456&scope=all
         *
         * 刷新密码 http://localhost:8080/oauth/token?grant_type=refresh_token&client_id=appId&client_secret=123456&refresh_token=1b46f93f-af95-4ce6-afae-618eca676ebc
         */
        clients.inMemory()
                // appid 表里取 这里写死
                .withClient("appId")
                // 密钥  表里取 这里写死
                .secret(passwordEncoder.encode("123456"))
                // 授权码
                .authorizedGrantTypes("authorization_code","password","client_credentials","refresh_token")
                // 作用域
                .scopes("all")
                // 资源的id  表里取 这里写死
                .resourceIds("mayikt_resource")
                // 回调地址  表里取 这里写死
                .redirectUris("http://www.mayikt.com/callback");
    }

}

contoller 认证token

@RestController
@RequestMapping("/oauth")
public class AuthorizationContoller {
     

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 校验token
     *
     * @param token
     * @return
     */
    @GetMapping("/checkToken")
    public String getCheckToken(String token){
     
        String url = "http://localhost:8080/oauth/check_token?token="+token;
        String forObject = restTemplate.getForObject(url, String.class);
        return forObject;
    }
}

yml

spring:
  redis:
    database: 0
    host: 127.0.0.1

server:
  port: 8080

密码模式获取token

密码模式获取 token http://localhost:8080/oauth/token?username=admin&password=123456&grant_type=password&client_id=appId&client_secret=123456&scope=all
oauth2整合security(密码模式)_第1张图片
refresh_token用来刷新token,刷新后原来的token立即失效

验证token
http://localhost:8080/oauth/checkToken?token=6dd755e7-ab40-4e77-a4ae-60ebba57aeaf
oauth2整合security(密码模式)_第2张图片
刷新token
刷新后原来的token就会失效
http://localhost:8080/oauth/token?grant_type=refresh_token&client_id=appId&client_secret=123456&refresh_token=1b46f93f-af95-4ce6-afae-618eca676ebc

jwt模式

<!‐‐JWT依赖‐‐>
 <dependency>
 	<groupId>io.jsonwebtokengroupId>
 	<artifactId>jjwtartifactId>
 	<version>0.9.1version>
 dependency>
<!‐‐JWT依赖‐‐>
 <dependency>
	 <groupId>io.jsonwebtokengroupId>
	 <artifactId>jjwtartifactId>
	 <version>0.9.1version>
 dependency>

Controller类,使用jjwt工具类来解析Authorization头中存储的JWT内容

    @GetMapping("/getCurrentUser")
    public Object getCurrentUser(Authentication authentication,
                                 HttpServletRequest request) {
     
        String header = request.getHeader("Authorization");
        String token = null;
        if (header != null) {
     
            token = header.substring(header.indexOf("bearer") + 7);
        } else {
     
            token = request.getParameter("access_token");
        }
        return Jwts.parser()
                .setSigningKey("123123".getBytes(StandardCharsets.UTF_8))
                .parseClaimsJws(token)
                .getBody();
    }

config

@Configuration
public class JwtTokenStoreConfig {
     

    @Bean
    public TokenStore jwtTokenStore() {
     
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
     
        JwtAccessTokenConverter accessTokenConverter = new
                JwtAccessTokenConverter();
        //配置JWT使用的秘钥
        accessTokenConverter.setSigningKey("123123");
        return accessTokenConverter;
    }
}

在授权服务器配置中指定令牌的存储策略为JWT
oauth2整合security(密码模式)_第3张图片
用密码模式测试
oauth2整合security(密码模式)_第4张图片

扩展JWT中的存储内容

有时候我们需要扩展JWT中存储的内容,这里我们在JWT中扩展一个 key为enhance,value为
enhance info 的数据。
继承TokenEnhancer实现一个JWT内容增强器

public class JwtTokenEnhancer implements TokenEnhancer {
     

    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken,
                                     OAuth2Authentication authentication) {
     
        Map<String, Object> info = new HashMap<>();
        info.put("enhance", "enhance info");
        ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info);
        return accessToken;
    }
}

创建一个JwtTokenEnhancer实例

@Bean
 public JwtTokenEnhancer jwtTokenEnhancer() {
     
 	return new JwtTokenEnhancer();
 }

在授权服务器配置中配置JWT的内容增强器

@Autowired
private JwtTokenEnhancer jwtTokenEnhancer;

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)throws Exception{
     
        //配置JWT的内容增强器
        TokenEnhancerChain enhancerChain=new TokenEnhancerChain();
        List<TokenEnhancer> delegates=new ArrayList<>();
        delegates.add(jwtTokenEnhancer);
        delegates.add(jwtAccessTokenConverter);
        enhancerChain.setTokenEnhancers(delegates);
        endpoints.authenticationManager(authenticationManagerBean) //使用密码模式需要配置
        .tokenStore(tokenStore) //配置存储令牌策略
        .accessTokenConverter(jwtAccessTokenConverter)
        .tokenEnhancer(enhancerChain) //配置tokenEnhancer
        .reuseRefreshTokens(false) //refresh_token是否重复使用
        .userDetailsService(userService) //刷新令牌授权包含对用户信息的检查
        .allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST); //支持GET,POST请求
        }

你可能感兴趣的:(mysql,数据结构,数据库)