Spring Security OAuth2单点登录

Spring Security OAuth2单点登录,第1张

Spring Security pom.xml:
<parent>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-parentartifactId>
    <version>2.5.4version>
    <relativePath/>
parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-securityartifactId>
    dependency>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>
    <dependency>
        <groupId>mysqlgroupId>
        <artifactId>mysql-connector-javaartifactId>
        <scope>runtimescope>
    dependency>
    <dependency>
        <groupId>org.projectlombokgroupId>
        <artifactId>lombokartifactId>
        <optional>trueoptional>
    dependency>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-testartifactId>
        <scope>testscope>
    dependency>
    <dependency>
        <groupId>org.springframework.securitygroupId>
        <artifactId>spring-security-testartifactId>
        <scope>testscope>
    dependency>
    <dependency>
        <groupId>com.baomidougroupId>
        <artifactId>mybatis-plus-boot-starterartifactId>
        <version>3.4.2version>
    dependency>
    <dependency>
        <groupId>org.slf4jgroupId>
        <artifactId>slf4j-apiartifactId>
    dependency>
    <dependency>
        <groupId>org.thymeleaf.extrasgroupId>
        <artifactId>thymeleaf-extras-springsecurity5artifactId>
    dependency>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-thymeleafartifactId>
    dependency>
dependencies>

thymeleaf-extras-springsecurity5:thymeleaf和Spring security的整合jar包

application.yml:
spring:
  datasource:
    username: root
    password: abcdefg
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springSecurityTest?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8

配置数据库

java 目录结构
config

​	securityConfig.java

controller

​	UserController.java

>hander

​	MyAccessDeniedHandler.java

​	MyAuthenticationFailureHandle.java

​	MyAuthenticationSuccessHandle.java

mapper

​	RoleMapper.java

​	UserMapper.java

pojo

​	Role.java

​	Users.java

service

​	MyAccess.java

​	MyAccessImpl.java

​	RoleService.java

​	UserService.java

​	UserDetailServiceImpl.java

B>包;I>接口;C>普通类

pojo

对应数据库的实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Role {
    private String uid;
    private String roleName;
    private String roleDesc;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Users {
    private Integer id;
    @TableId(type = IdType.ASSIGN_UUID)
    private String uid;
    private String username;
    private String password;
}

@TableId(type = IdType.ASSIGN_UUID):使用uid

mapper

使用mybatisPlus *** 作数据库

@Mapper
public interface RoleMapper extends BaseMapper<Role> {
}
@Mapper
public interface UsersMapper extends BaseMapper<Users> {
}
service

查询用户表的用户uid,username,paddword信息,再根据uid查询角色表对应用户角色权限

@Service
public class RoleService {
    @Autowired
    private RoleMapper roleMapper;

    public List<Role> selectRole(String uid) {
        return roleMapper.selectList(new QueryWrapper<Role>().eq("uid",uid));
    }
}
@Service
public class UsersService {
    @Autowired
    private UsersMapper usersMapper;

    public Users selectUsername(String username) {
        return usersMapper.selectOne(new QueryWrapper<Users>().eq("username", username));
    }
}

自定义登录认证逻辑

@Service
@Slf4j
public class UserDetailServiceImpl implements UserDetailsService {
    @Autowired
    private UsersService usersService;
    @Autowired
    private RoleService roleService;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        //根据用户名去数据库查询,不存在就抛异常UsernameNotFoundException
        Users user = usersService.selectUsername(s);
        if (user == null) {
            throw new UsernameNotFoundException("用户名不存在");
        }
        List<Role> roles = roleService.selectRole(user.getUid());
      	//创建list集合用来存储用户的权限角色
        ArrayList<SimpleGrantedAuthority> authorities = new ArrayList<>();
        if (roles.size() >= 1) {
            for (Role role : roles) {
                authorities.add(new SimpleGrantedAuthority(role.getRoleName()));
            }
        }
        log.info("执行自定义登录逻辑");
        log.info("角色权限:" + authorities);
      	//这个User是Security包下的User,第一个参数username,第二个参数passowrd(已加密过的),第三个参数角色权限
        return new User(s, user.getPassword(), authorities);
    }
}

自定义access

public interface MyAccess {
    boolean hasPermission(HttpServletRequest request, Authentication authentication);
}
@Service
public class MyAccessImpl implements MyAccess {
    @Override
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        Object obj = authentication.getPrincipal();
        if (obj instanceof UserDetails) {
            UserDetails userDetails = (UserDetails) obj;
            Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
            return authorities.contains(new SimpleGrantedAuthority(request.getRequestURI()));
        }
        return false;
    }
}
config

设置访问权限

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;
    @Autowired
    private DataSource dataSource;
    @Autowired
    private PersistentTokenRepository persistentTokenRepository;
    @Autowired
    private UserDetailServiceImpl userDetailService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                //登录页面
                .loginPage("/toLogin")
                //登录表单提交的求情
                .loginProcessingUrl("/login")
                //登录成功跳转页面,这个是一个请求必须是post
//                .successForwardUrl("/index")
                //自定义登录成功的处理器
                .successHandler(new MyAuthenticationSuccessHandler("/index.html"))
                //登录错误跳转页面,这个是一个请求必须是post
//                .failureForwardUrl("/toError")
                //自定义登录失败的处理器
                .failureHandler(new MyAuthenticationFailureHandler("/error.html"))
                //自定义表单的name,默认就是username和password
//                .usernameParameter("username")
//                .passwordParameter("password")
                .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/toLogin")
                .and()
                //认证
                .authorizeRequests()
                //登录页面和错误页面放行不拦截
                .antMatchers("/loginPage.html","/error.html","/toLogin")
                .permitAll()
                //权限访问,权限是随便的比如lv1,lv2等,可以设置多个权限或角色比如既是lv1又是lv2
                .antMatchers("/lv1.html").hasAnyAuthority("lv1")
                .antMatchers("/lv2.html").hasAnyAuthority("lv2")
                .antMatchers("/lv3.html").hasAnyAuthority("lv3")
                //角色访问必须是ROLE_xxx形式
                .antMatchers("/lv4.html").hasRole("hzyy")
                //ip地址
                .antMatchers("/ip.html").hasIpAddress("127.0.0.1")
                //自定义access,使用自定义的access就不能使用anyxxx的方法
//                .anyRequest().access("@myAccessImpl.hasPermission(request,authentication)")
                //其余所有请求
                .anyRequest()
                //需要认证
                .authenticated()
                .and()
                .exceptionHandling()
                .accessDeniedHandler(myAccessDeniedHandler);
        http.rememberMe()
                .tokenRepository(persistentTokenRepository)
                //默认就是remember-me
                //.rememberMeParameter("remember-me")
                .tokenValiditySeconds(60)
                .userDetailsService(userDetailService);
    }


    /**
     * 密码加密和匹配
     * @return 加密
     */
    @Bean
    public PasswordEncoder getPW() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        //第一次需要打开会自动创建一张表
        //jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }
}
handler

没有权限跳转的页面也就是403页面

@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
        httpServletResponse.setStatus(HttpServletResponse.SC_ACCEPTED);
        httpServletResponse.setHeader("Content-Type","application/json;charset=utf-8");
        PrintWriter writer = httpServletResponse.getWriter();
        writer.write("{\"status\":\"error403\",\"msg:权限不足\"}");
        writer.flush();
        writer.close();
    }
}

自定义登录失败的逻辑,也可以使用自带的

public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
    private String url;

    public MyAuthenticationFailureHandler(String url) {
        this.url = url;
    }

    @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        httpServletResponse.sendRedirect(url);
    }
}

自定义登录成功的逻辑,也可以使用自带的

public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    private String url;

    public MyAuthenticationSuccessHandler(String url) {
        this.url = url;
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        User user = (User) authentication.getPrincipal();
        /**
         * org.springframework.security.core.userdetails.User
         * [Username=hzyy, Password=[PROTECTED], Enabled=true,
         * AccountNonExpired=true, credentialsNonExpired=true,
         * AccountNonLocked=true, Granted Authorities=[lv2, lv3]]
         */
        log.info("security的user:" + user);
        log.info("ip:" + httpServletRequest.getRemoteAddr());
        httpServletResponse.sendRedirect(url);
    }
}
Other
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true,proxyTargetClass = true,jsr250Enabled = true)
@SpringBootApplication
public class SpringSecuritySeniorApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringSecuritySeniorApplication.class, args);
    }

}

启动类使用注解@EnableGlobalMethodSecurity开启security的注解使用,参数有四个分别对应一个注解,最好用的一个:

prePostEnabled:对应注解为@PreAuthorize,参数为表达式,可以设置权限角色

@PreAuthorize("hasAnyAuthority('lv1')")
@RequestMapping("/toAnn")
public String annotation() {
   return "redirect:annotation.html";
}

密码加密,使用的security默认的加密方式

PasswordEncoder是个接口,但在config里面已经进行了bean注入

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

@Test
void contextLoads() {
    System.out.println(passwordEncoder.encode("hahha"));
}

自定义错误页面的展示

public class ErrorPageConfig implements ErrorPageRegistrar {
    @Override
    public void registerErrorPages(ErrorPageRegistry registry) {
        ErrorPage page404 = new ErrorPage(HttpStatus.NOT_FOUND, "/404");
        ErrorPage page403 = new ErrorPage(HttpStatus.FORBIDDEN, "/403");
        ErrorPage page500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/500");
        registry.addErrorPages(page403,page404,page500);
    }
}
@Configuration
public class ErrorBean {
    @Bean
    public ErrorPageConfig errorPageConfig (){
        return new ErrorPageConfig();
    }
}
JWT

JsonWebToken

JWT pom.xml
<dependency>
    <groupId>io.jsonwebtokengroupId>
    <artifactId>jjwtartifactId>
    <version>0.9.1version>
dependency>
java
package com.xiaoyu;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.Base64Codec;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import sun.misc.BASE64Decoder;

import java.util.Date;

@SpringBootTest
class SpringSecurityJwtApplicationTests {

    @Test
    void creatToken() {
        JwtBuilder jwtBuilder = Jwts.builder()
                //唯一id
                .setId("666")
                //接受的用户
                .setSubject("Rose")
                //签发时间
                .setIssuedAt(new Date())

                //签名算法+密钥
                .signWith(SignatureAlgorithm.HS256, "hzyyyyyyyy");
        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]));
    }

    @Test
    public void AnalysisToken() {
        String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI2NjYiLCJzdWIiOiJSb3NlIiwiaWF0IjoxNjMxMjgxNTUxfQ.cWEbwr3FjzM8oyQgEEEG3-M1Im6JJ1bpSxol00WHrpY";
        //Claims JWT的荷载对象
        Claims claims = (Claims) Jwts.parser()
                .setSigningKey("hzyyyyyyy")
                .parse(token)
                .getBody();
        System.out.println("id" + claims.getId());
        System.out.println("rose" + claims.getSubject());
        System.out.println("date" + claims.getIssuedAt());
    }

//设置失效时间
    @Test
    void creatTokenTimeout() {
        long data = System.currentTimeMillis();
        long exp = data+60*1000;
        JwtBuilder jwtBuilder = Jwts.builder()
                //唯一id
                .setId("666")
                //接受的用户
                .setSubject("Rose")
                //签发时间
                .setIssuedAt(new Date())
                //设置失效时间
                .setExpiration(new Date(exp))
                //签名算法+密钥
                .signWith(SignatureAlgorithm.HS256, "hzyyyyyyyy");
        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]));
    }

    @Test
    public void AnalysisTokenTimeout() {
        /*
        解析失效会报错
        io.jsonwebtoken.ExpiredJwtException
         */
        String token = "eyJhbGciOiJIUzI1NiJ9." +
                "eyJqdGkiOiI2NjYiLCJzdWIiOiJSb3NlIiwiaWF0IjoxNjMxMjgyMDQ2LCJleHAiOjE2MzEyODIxMDZ9." +
                "qSG3daBcCRQ92-p564daNgN7UPbquVz85c14zcj8rdQ";
        //Claims JWT的荷载对象
        Claims claims = (Claims) Jwts.parser()
                .setSigningKey("hzyyyyyyyy")
                .parse(token)
                .getBody();
        System.out.println("id" + claims.getId());
        System.out.println("rose" + claims.getSubject());
        System.out.println("date" + claims.getIssuedAt());
    }

//自定义声明
    @Test
    void creatTokenZDY() {
        JwtBuilder jwtBuilder = Jwts.builder()
                //唯一id
                .setId("666")
                //接受的用户
                .setSubject("Rose")
                //签发时间
                .setIssuedAt(new Date())
                //添加自定义
                .claim("name","zhangsan")
                .claim("logo","xxx.jpg")
                //签名算法+密钥
                .signWith(SignatureAlgorithm.HS256, "hzyyyyyyyy");
        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]));
    }

    @Test
    public void AnalysisTokenZDY() {
        String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI2NjYiLCJzdWIiOiJSb3NlIiwiaWF0IjoxNjMxMjgyMzc3LCJuYW1lIjoiemhhbmdzYW4iLCJsb2dvIjoieHh4LmpwZyJ9.QuI6RAqoZ88nHrih3xA5dcT3SaWNFYrkobhGpNR5YEw";
        //Claims JWT的荷载对象
        Claims claims = (Claims) Jwts.parser()
                .setSigningKey("hzyyyyyyyy")
                .parse(token)
                .getBody();
        System.out.println("id:" + claims.getId());
        System.out.println("rose:" + claims.getSubject());
        System.out.println("date:" + claims.getIssuedAt());
        System.out.println("name:" + claims.get("name"));
        System.out.println("logo:" + claims.get("logo"));
    }
}
OAuth2
OAuth2

OAuth是一个协议有很多对应语言的实现,这使用的spring的实现

Oauth2有四种模式

1.授权码模式:例如登录页面的其他账号登录中使用微信登录

2.简化版的授权码模式

3.密码模式:使用密码登录获取token

4.客户端模式

pom.xml

注意Spring boot和Spring cloud的版本对应

<parent>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-parentartifactId>
    <version>2.3.5.RELEASEversion>
    <relativePath/> 
parent>
<properties>
    <java.version>1.8java.version>
    <spring-cloud.version>Hoxton.SR9spring-cloud.version>
properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-starter-oauth2artifactId>
    dependency>
    <dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-starter-securityartifactId>
    dependency>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-testartifactId>
        <scope>testscope>
    dependency>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-data-redisartifactId>
    dependency>
    <dependency>
        <groupId>io.jsonwebtokengroupId>
        <artifactId>jjwtartifactId>
        <version>0.9.1version>
    dependency>
dependencies>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-dependenciesartifactId>
            <version>${spring-cloud.version}version>
            <type>pomtype>
            <scope>importscope>
        dependency>
    dependencies>
dependencyManagement>
java

创建认证类继承UserDetailsService,重写loadUserByUsername()方法

@Service
public class UserService implements UserDetailsService {
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        String password = passwordEncoder.encode("123");
        return new User(s,password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
    }
}

创建权限类继承WebSecurityConfigurerAdapter,重写configure(HttpSecurity http)方法

bean注入PasswordEncoder,返回为BCryptPasswordEncoder():密码加密

AuthenticationManager,返回为super.authenticationManager():jwt自添加内容时要用到

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

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

        http.authorizeRequests()
                .antMatchers("/oauth/**","/login/**").permitAll().anyRequest()
                .authenticated().and().formLogin().permitAll().and()
                .csrf().disable();
    }

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

    @Override
    @Bean
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }
}

创建jwt存储类

TokenStore:声明存储token为jwt

JwtAccessTokenConverter:添加jwt密钥

JwtTokenEnhancer:后面jwt添加自定义内容要用到

@Configuration
public class JwtTokenStoreConfig {

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

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        jwtAccessTokenConverter.setSigningKey("miyaonamelenght");
        return jwtAccessTokenConverter;
    }

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

jwt添加自定义内容类,继承TokenEnhancer重写enhance(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication)方法

map类型可以添加多个

public class JwtTokenEnhancer implements TokenEnhancer {
    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication) {
        Map<String,Object> map = new HashMap<>();
        map.put("uid","hzyy");
        ((DefaultOAuth2AccessToken)oAuth2AccessToken).setAdditionalInformation(map);
        return oAuth2AccessToken;
    }
}

授权服务器类,继承AuthorizationServerConfigurerAdapter

必须加注解@EnableAuthorizationServer开启授权服务

passwordEncoder:密码加密

authenticationManager:认证管理

userService:认证服务

jwtTokenStore:jwtToken存储

JwtTokenEnhancer:jwtToken增加自定义内容用

jwtAccessTokenConverter:jwtToken转换器

configure(ClientDetailsServiceConfigurer clients):配置授权服务器

configure(AuthorizationServerEndpointsConfigurer endpoints):配置jwt自定义内容

configure(AuthorizationServerSecurityConfigurer security):获取密钥要认证,单点登录需要

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

    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserService userService;

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

    @Autowired
    private JwtTokenEnhancer jwtTokenEnhancer;

    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;

    //http://localhost:8080/oauth/authorize?response_type=code&client_id=client&redirct_url=http://localhost:8080/getCode&scope=all
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                //客户端id
                .withClient("client")
                //密钥
                .secret(passwordEncoder.encode("112233"))
                //重定向地址
                .redirectUris("http://localhost:8080/getCode")
                //授权范围
                .scopes("all")
                //token失效时间
                .accessTokenValiditySeconds(600)
                //授权类型  authorization_code:授权吗模式;password 密码模式 refresh_token刷新令牌
                .authorizedGrantTypes("authorization_code","password","refresh_token")
                //刷新令牌的失效时间
                .refreshTokenValiditySeconds(6000)
                //自动授权不需要点击确定
                .autoApprove(true);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        //设置增强内容
        TokenEnhancerChain chain = new TokenEnhancerChain();
        List<TokenEnhancer> delegates = new ArrayList<>();
        delegates.add(jwtTokenEnhancer);
        delegates.add(jwtAccessTokenConverter);
        chain.setTokenEnhancers(delegates);
        endpoints.authenticationManager(authenticationManager)
                .userDetailsService(userService)
                .tokenStore(jwtTokenStore)
                .accessTokenConverter(jwtAccessTokenConverter)
                .tokenEnhancer(chain);
    }

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

资源服务器类,继承ResourceServerConfigurerAdapter,重写configure(HttpSecurity http)

需要注意的是:

  1. 加注解@EnableResourceServer开启资源服务
  2. 一定要先全部拦截然后认证进行放行

必须先.authorizeRequests().anyRequest().authenticated()再.requestMatchers().antMatchers(“/user/**”);不然会报错

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .requestMatchers()
                .antMatchers("/user/**");
    }
}

如果资源服务器和授权服务器分离的话需要多两个步骤

  1. jwtToken存储配置
@Configuration
public class JwtTokenStoreConfig {

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

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        //设置jwt密钥
        jwtAccessTokenConverter.setSigningKey("miyaonamelenght");
        return jwtAccessTokenConverter;
    }
}
  1. 添加jwt验证

    和授权服务器资源服务器在一起的区别就是要添加jwtToken认证

    @Autowired
    @Qualifier("jwtTokenStore")
    private TokenStore jwtToken;
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.tokenStore(jwtToken);
    }
    
    @Configuration
    @EnableResourceServer
    public class ResourceConfig extends ResourceServerConfigurerAdapter {
        @Autowired
        @Qualifier("jwtTokenStore")
        private TokenStore jwtToken;
        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources.tokenStore(jwtToken);
        }
    
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.csrf().disable()
                    .authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                    .requestMatchers()
                    .antMatchers("/user/**");
        }
    }
    

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/874924.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-13
下一篇 2022-05-13

发表评论

登录后才能评论

评论列表(0条)