0


权限管理 springboot集成springSecurity Oauth2 JWT

一、SpringSeurity的基础操作

1、引入主要依赖

      <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

此时我们在启动项目时会发现对于的页面都需要登录才能访问!默认用户名、密码是user,密码是控制台启动时打印的密码。

2、加密器

官方推荐使用BCryptPasswordEncoder这是一个基于Hash单向加密的加密类

    @Test
    public void contextLoads(){
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        //密码加密
        String encode = bCryptPasswordEncoder.encode("123");
        System.out.println(encode);
        System.out.println("==========================");
        //密码匹配,匹配成功返回true,否则返回false
        boolean matches = bCryptPasswordEncoder.matches("123", encode);
        System.out.println(matches);

    }

打印结果:

在项目使用时一般将其放到Spring容器中

@Configuration
public class SecurityConfig {

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

3、实现自定义登录逻辑

实现SpringSecurity里的UserDetailsService接口的LoadUserByUsername方法便可以实现自定义登录逻辑。以下代码将实现用户名为admin,密码为123的登录。一旦使用了自定义登录逻辑,原本的user和打印的password登录将不再生效。此时,通过admin 123便可登录。

对于登出SpringSecurity也提供了一个/logout的接口。

SpringSecurity框架以为我们提供了一个需要username和passsword参数的登录接口/login 的post请求,需要登录时框架调用的便是该接口。

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //查询数据库判断用户名是否操作,如果不存在就会抛出UsernameNotFoundException异常
        if (!"admin".equals(username)) {
            throw new UsernameNotFoundException("用户名不存在!");
        }
        //2、把查询出来的密码(注册时已经加密过)进行解析,或者直接把密码放入构造方法
        String password = passwordEncoder.encode("123");
        return new User(username, password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal,ROLE_abc"));
    }
}

4、访问限制

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        //授权认证
        http.authorizeRequests()
                //error.html不需要被认证
                .antMatchers("/error.html").permitAll()
                //login.html不需要被认证
                .antMatchers("/login.html").permitAll()
                //指定角色访问
                .antMatchers("/main.html").hasRole("abc")
                //指定权限访问
                .antMatchers("/main.html").hasAuthority("admin")
                //多个权限都可访问
                .antMatchers("/main.html").hasAnyAuthority("admin,normal")
                //多个角色都可以访问
                .antMatchers("/main.html").hasAnyRole("ABC,abc")
                //通过指定ip地址进行访问,注意这里的ip与localhost转换的ip是不一样的,线上一般为服务器ip
                .antMatchers("/main.html").hasIpAddress("127.0.0.1")
                //所有请求都必须被认证,必须登录之后被访问
                .anyRequest().authenticated();

        //关闭csrf防护
        http.csrf().disable();
    }
}

在访问限制配置时,我们只需要集成WebSecurityConfigurerAdapter配置类configure(HttpSecurity http)方法即可。

多个角色也类似:注意角色这里不要加前缀ROLE_

对应之前服务实现类的权限和角色:

5、自定义异常处理

首先添加异常处理类实现AccessDeniedHandler接口的handle方法,handle方法里可自定义处理SpringSecurity的403等异常的处理。

@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
        //设置响应状态码
        httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
        httpServletResponse.setHeader("Content-Type", "application/json;charset=utf-8");
        PrintWriter writer = httpServletResponse.getWriter();
        writer.write("{\"status\":\"error\",\"msg\":\"权限不足,请联系管理员\"}");
        writer.flush();
        writer.close();
    }
}

之后在SpringSecurity配置类里添加如下:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //注入异常处理类
    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;

    ......

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        ......

        //异常处理的配置
        http.exceptionHandling()
                .accessDeniedHandler(myAccessDeniedHandler);
    }
}

当权限不足报403时,这里会调用我们自定义的方法:

6、通过注解的方式配置访问控制

** 角色控制访问:注意这里的ROLE_前缀不能去**

其他类开启注解@EnableGlobalMethodSecurity(securedEnabled = true)

控制类里添加@Secured(角色名)注解进行角色访问控制

当用户有ROLE_abC角色时会被允许访问,否则会报500错误!

使用@PreAuthorize注解来进行访问控制

类似的,启动类里的参数不同而已:

进行角色访问控制:@PreAuthorize("hasRole('abc')") //此时,有无ROLE_前缀都是可以被访问到的。要注意的时配置类里的hasRole方法是不允许以ROLE_前缀开头的这里有些差别。

同时也可用于权限控制访问:@PreAuthorize("hasAuthority('admin')")

二、Auth2认证方案

1、什么是Auth2认证

2、Oauth2最常用的授权模式

3、依赖引入

使用Oauth2时我们在SpringSecurity的依赖上添加如下依赖:

       <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>

4、添加配置类

(1)授权模式的配置类如下

SpringSecuirty的配置类:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

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

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

Oauth2的授权服务器配置:

@Configuration
@EnableAuthorizationServer  //开启授权服务器
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                //配置client-id
                .withClient("admin")
                //配置client-secret
                .secret(passwordEncoder.encode("112233"))
                //配置访问token的有效期
//                .accessTokenValiditySeconds(3600)
                //配置redirect_uri,用于授权成功后跳转
                .redirectUris("http://www.baidu.com")
                //配置申请的权限范围
                .scopes("all")
                //配置grant_type,表示授权类型
                .authorizedGrantTypes("authorization_code");

    }
}

Oauth2的资源服务器的配置类:

@Configuration
@EnableResourceServer  //开启资源服务器
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .requestMatchers()
                .antMatchers("/user/**");
    }
}

密码模式的配置类如下:

SpringSecurity配置类:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

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

    //用于密码认证
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception{
        return super.authenticationManagerBean();
    }

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

授权服务器配置:

@Configuration
@EnableAuthorizationServer  //开启授权服务器
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    //使用密码模式配置所需配置
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                //配置client-id
                .withClient("admin")
                //配置client-secret
                .secret(passwordEncoder.encode("112233"))
                //配置访问token的有效期
//                .accessTokenValiditySeconds(3600)
                //配置redirect_uri,用于授权成功后跳转
                .redirectUris("http://www.baidu.com")
                //配置申请的权限范围
                .scopes("all")
                //配置grant_type,表示授权类型
                .authorizedGrantTypes("password");

    }
}

资源服务器配置:

与授权获取token时的一样

5、测试

启动服务器

授权模式获取接口资源的步骤

(1)获取授权码:

http://localhost:8080/oauth/authorize?response_type=code&client_id=admin&redirect_uri=http://www.baidu.com&scope=all

选择支持认证。

认证后记录下这个code里的值:

(2)获取令牌

用户名、密码就是授权服务器里的用户名密码

填写对应参数:

发生请求:

(3)获取我们自己写的接口的数据:

选择Bearer auth认证填入对应token

获取到对应用户信息:

** 加密模式获取资源的步骤**

(1)通过授权服务获取token

认证配置与授权时一样

传入参数有所不同:

通过用户名密码获取到对应token

** (2)获取对应接口资源,与之前授权模式获取接口之源一样**

6、存在到Redis里,后续推荐使用JWT

以上授权的数据是放到内存中的实际开发过程中应将其放到redis里

(1)添加redis依赖与配置

       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
spring:
  redis:
    database: 1
    host: my-server
    port: 6380
    password: 

(2)配置类

@Configuration
public class RedisConfig {

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @Bean
    public TokenStore redisTokenStore(){
        return new RedisTokenStore(redisConnectionFactory);
    }
}
@Configuration
@EnableAuthorizationServer  //开启授权服务器
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    @Qualifier("redisTokenStore")
    private TokenStore tokenStore;

    //使用密码模式配置所需配置
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService)
                .tokenStore(tokenStore);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                //配置client-id
                .withClient("admin")
                //配置client-secret
                .secret(passwordEncoder.encode("112233"))
                //配置访问token的有效期
//                .accessTokenValiditySeconds(3600)
                //配置redirect_uri,用于授权成功后跳转
                .redirectUris("http://www.baidu.com")
                //配置申请的权限范围
                .scopes("all")
                //配置grant_type,表示授权类型
                .authorizedGrantTypes("password");

    }
}

放到获取token的接口后可以看到:数据已存在redis中去了

三、JWT认证机制

1、JWT的组成

JWT是由

.

分割的如下三部分组成:

头部(Header)

Header 一般由两个部分组成:

  • alg
  • typ
alg

是是所使用的hash算法,如:HMAC SHA256或RSA,

typ

是Token的类型,在这里就是:JWT。

{
  "alg": "HS256",
  "typ": "JWT"
}

然后使用Base64Url编码成第一部分:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.<second part>.<third part>

载荷(Payload)

这一部分是JWT主要的信息存储部分,其中包含了许多种的声明(claims)。

Claims的实体一般包含用户和一些元数据,这些claims分成三种类型:

  • reserved claims:预定义的 一些声明,并不是强制的但是推荐,它们包括 iss (issuer), exp (expiration time), sub (subject),aud(audience) 等(这里都使用三个字母的原因是保证 JWT 的紧凑)。
  • public claims: 公有声明,这个部分可以随便定义,但是要注意和 IANA JSON Web Token 冲突。
  • private claims: 私有声明,这个部分是共享被认定信息中自定义部分。

一个简单的Pyload可以是这样子的:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

这部分同样使用Base64Url编码成第二部分:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.<third part>

签名(Signature)

Signature是用来验证发送者的JWT的同时也能确保在期间不被篡改。

在创建该部分时候你应该已经有了编码后的Header和Payload,然后使用保存在服务端的秘钥对其签名,一个完整的JWT如下:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

因此使用JWT具有如下好处:

  • 通用:因为json的通用性,所以JWT是可以进行跨语言支持的,像JAVA,JavaScript,NodeJS,PHP等很多语言都可以使用。
  • 紧凑:JWT的构成非常简单,字节占用很小,可以通过 GET、POST 等放在 HTTP 的 header 中,非常便于传输。
  • 扩展:JWT是自我包涵的,包含了必要的所有信息,不需要在服务端保存会话信息, 非常易于应用的扩展。

2、依赖引入

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

3、生成JWT的测试

    private void createToken() {
        //当前系统时间
        long now = System.currentTimeMillis();
        //过期时间,1分钟
        long exp = now + 60 * 1000;

        //创建JwtBuilder对象
        JwtBuilder jwtBuilder = Jwts.builder()
                //声明的标识{“jti”:"8888"}
                .setId("8888")
                //主体,用户{“sub”:"Rose"}
                .setSubject("Rose")
                //创建日期{“ita”:“xxxxxx”}
                .setIssuedAt(new Date())
                .signWith(SignatureAlgorithm.HS256, "xxxxxx")
                //设置过期时间
                .setExpiration(new Date(exp));
        //获取jwt的token
        String token = jwtBuilder.compact();
        System.out.println(token);

        System.out.println("=======================================");
        String[] split = token.split("\\.");
        System.out.println(Base64Codec.BASE64.decodeToString(split[0]));
        System.out.println(Base64Codec.BASE64.decodeToString(split[1]));
        //无法解密
        System.out.println(Base64Codec.BASE64.decodeToString(split[2]));
    }

打印如下:密码盐一般为服务器的私钥

4、解析JWT

    private void parseJWT() {
        String jwt = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODg4Iiwic3ViIjoiUm9zZSIsImlhdCI6MTY2NTAzNzc0MSwiZXhwIjoxNjY1MDM3ODAxfQ.jGZrGW0sYyfuatsi1xtYXI8pPflRZR4DY3BbwmSKN0M";
        //解析token获取负载中声明的对象
        Claims claims = Jwts.parser()
                .setSigningKey("xxxxxx")
                .parseClaimsJws(jwt)
                .getBody();
        System.out.println("id:" + claims.getId());
        System.out.println("subject:" + claims.getSubject());
        System.out.println("issuedAt:" + claims.getIssuedAt());
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("签发时间:" + simpleDateFormat.format(claims.getIssuedAt()));
        System.out.println("过期时间:" + simpleDateFormat.format(claims.getExpiration()));
        System.out.println("当前时间:" + simpleDateFormat.format(new Date()));
    }

5、自定义声明

    //自定义声明
    private void createJWTByClaims() {
        //当前系统时间
        long now = System.currentTimeMillis();
        //过期时间,1分钟
        long exp = now + 60 * 1000;

        //创建JwtBuilder对象
        JwtBuilder jwtBuilder = Jwts.builder()
                //声明的标识{“jti”:"8888"}
                .setId("8888")
                //主体,用户{“sub”:"Rose"}
                .setSubject("Rose")
                //创建日期{“ita”:“xxxxxx”}
                .setIssuedAt(new Date())
                .signWith(SignatureAlgorithm.HS256, "xxxxxx")
                //设置过期时间
                .setExpiration(new Date(exp))
                //自定义声明的使用
                .claim("roles", "admin")
                .claim("logo", "xxx.jpg");
        //直接传入Map
//                .setClaims(map)
        //获取jwt的token
        String token = jwtBuilder.compact();
        System.out.println(token);
    }

解析:

private void parseJWTClaims() {
        String jwt = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODg4Iiwic3ViIjoiUm9zZSIsImlhdCI6MTY2NTAzODQwMiwiZXhwIjoxNjY1MDM4NDYxLCJyb2xlcyI6ImFkbWluIiwibG9nbyI6Inh4eC5qcGcifQ.fzyWQ_HG725kDoZ0zljHkIiIrO1mhl_u77r81ZeT1FA";
        //解析token获取负载中声明的对象
        Claims claims = Jwts.parser()
                .setSigningKey("xxxxxx")
                .parseClaimsJws(jwt)
                .getBody();
        System.out.println("id:" + claims.getId());
        System.out.println("subject:" + claims.getSubject());
        System.out.println("issuedAt:" + claims.getIssuedAt());
        System.out.println("roles:" + claims.get("roles"));
        System.out.println("logo:" + claims.get("logo"));
    }

四、SpringSecurityOauth2整合JWT

1、添加配置类

Jwt的配置类

@Configuration
public class JwtTokenStoreConfig {

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

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

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

Jwt内容增强器的配置类:

public class JwtTokenEnhancer implements TokenEnhancer {

    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication) {
        Map<String, Object> info = new HashMap<>();
        //放入jwt里的内容
        info.put("enhance", "enhance info");
        ((DefaultOAuth2AccessToken) oAuth2AccessToken).setAdditionalInformation(info);
        return oAuth2AccessToken;
    }
}

授权服务器配置类:

@Configuration
@EnableAuthorizationServer  //开启授权服务器
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    @Qualifier("jwtTokenStore")
    private TokenStore tokenStore;

    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;

    @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(authenticationManager)
                .userDetailsService(userDetailsService)
                //配置存储令牌策略
                .tokenStore(tokenStore)
                .accessTokenConverter(jwtAccessTokenConverter)
                //配置内容增强器
                .tokenEnhancer(enhancerChain);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                //配置client-id
                .withClient("admin")
                //配置client-secret
                .secret(passwordEncoder.encode("112233"))
                //配置访问token的有效期
                .accessTokenValiditySeconds(3600)
                //配置刷新令牌的有效期
                .refreshTokenValiditySeconds(864000)
                //配置redirect_uri,用于授权成功后跳转
                .redirectUris("http://localhost:8081/login")
                //配置申请的权限范围
                .scopes("all")
                //配置grant_type,表示授权类型, 刷新令牌
                .authorizedGrantTypes("password","refresh_token");
    }
}

重启项目:

使用正确密码模式的访问接口进行测试:可以看到目前的token已经是JWT的token了

将此token放到官网解析可以看到对应增加的信息:

2、Jwt的解析

这里需要引入之前集成JWT的依赖

添加访问接口进行测试

    @GetMapping("/getCurrentUser")
    public Object getCurrentUser(Authentication authentication, HttpServletRequest request) {
        String head = request.getHeader("Authorization");
        String token = head.substring(head.indexOf("bearer") + 7);
        return Jwts.parser()
                .setSigningKey("test_key".getBytes(StandardCharsets.UTF_8))
                .parseClaimsJws(token)
                .getBody();
    }

访问该接口,仅需传入请求头Authorization和对应的bearer+JWT即可:

解析完毕:

3、刷新token

授权服务器配置如下:

再次测试:可以看到刷新时的token

五、SpringSecurityOauth2实现单点登录

我以之前的授权服务器作为授权服务器,现在在创建一个服务器作为单点请求登录的服务器客户端。依赖与授权服务器相同。

1、添加对应配置

server:
  port: 8081
  servlet:
    session:
      # 防止Cookie冲突,冲突会导致登录验证不通过
      cookie:
        name: OAUTH2-CLIENT-SESSIONID01
# 授权服务器地址
oauth2-server-url: http://localhost:8080
# 与授权服务器对应的配置
security:
  oauth2:
    client:
      client-id: admin
      client-secret: 112233
      user-authorization-uri: ${oauth2-server-url}/oauth/authorize
      access-token-uri: ${oauth2-server-url}/oauth/token
    resource:
      jwt:
        key-uri: ${oauth2-server-url}/oauth/token_key

使用单点登录时授权服务器的授权配置类:

@Configuration
@EnableAuthorizationServer  //开启授权服务器
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    @Qualifier("jwtTokenStore")
    private TokenStore tokenStore;

    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;

    @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(authenticationManager)
                .userDetailsService(userDetailsService)
                //配置存储令牌策略
                .tokenStore(tokenStore)
                .accessTokenConverter(jwtAccessTokenConverter)
                //配置内容增强器
                .tokenEnhancer(enhancerChain);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                //配置client-id
                .withClient("admin")
                //配置client-secret
                .secret(passwordEncoder.encode("112233"))
                //配置访问token的有效期
                .accessTokenValiditySeconds(3600)
                //配置刷新令牌的有效期
                .refreshTokenValiditySeconds(864000)
                //配置redirect_uri,用于授权成功后跳转
                .redirectUris("http://localhost:8081/login")
                //自动授权配置
                .autoApprove(true)
                //配置申请的权限范围
                .scopes("all")
                //配置grant_type,表示授权类型, 刷新令牌
                .authorizedGrantTypes("password", "refresh_token", "authorization_code");
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        //获取密钥需要身份认证,使用单点登录时必须配置
        security.tokenKeyAccess("isAuthenticated()");
    }
}

访问客户端的接口:

http://localhost:8081/user/getCurrentUser

此时,会跳转到授权服务器的登录页面:

登录成功访问到对应接口资源:

总结到此。

标签: spring boot java spring

本文转载自: https://blog.csdn.net/qq_50909707/article/details/127165284
版权归原作者 Dragon Wu 所有, 如有侵权,请联系我们删除。

“权限管理 springboot集成springSecurity Oauth2 JWT”的评论:

还没有评论