Spring security 多端多用户实战、认证鉴权扩展深入

当你阅读这篇文章的时候,我们假设你已经对Spring security有所了解,并且懂得如何初步使用。

前言

  1. 当你阅读这篇文章的时候,我们假设你已经对Spring security有所了解,并且懂得如何初步使用。
    如果不是,你可以先通过其他文档先了解Spring security,以及如何在Spring Boot项目中集成Spring security。
  2. Spring security是一款过度设计的安全框架,设计者为使用者准备了强大的功能和扩展方法,这导致了它十分复杂和繁琐,无法做到开箱即用,扩展起来也十分麻烦,很容易掉进坑里爬不出来。
  3. 同时,Spring security只提供了账号密码的登录方法,这在实际项目中往往是不够用的,这需要我们去扩展定制其他的登录的方法,这篇文章会介绍如何扩展登录方法。
  4. 这篇文章旨在帮助你如何快速地在你的项目中应用Spring security实现登录认证、鉴权的功能,作者水平有限,如有错漏,欢迎指出。

从配置开始搭建

  1. 引入依赖
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
  1. 添加配置文件
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     * 此方法配置 认证方法
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        super.configure(auth);
    }

    /**
     * 过滤器配置方法
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
    }

    /**
     * http安全配置
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
    }
}

从实战场景开始

从这里开始,我们开始配置认证方法,我们假设,实战项目中有多种用户,多种认证方法。
比如我们开发一个一个图书借阅系统,有APP、学生端小程序、管理端小程序、管理后台。
用户类型有:APP 有学生和管理员两种用户 、学生端小程序有学生用户,管理端小程序有管理员用户、管理后台有管理员用户。
这样用户、终端就是这样的关系
在这里插入图片描述
好了,一步一步来。

从基础的账号密码开始

基础部分 不会很详细,如果你还不熟悉spring security,建议先从其他文章开始
首先,我们先实现账号密码登录。

账号1
  1. 定义一个User类:
@Data
public class User {
    private String userId;
    private String account;
    private String password;
}

想要实现认证,就要实现Spring Security的UserDetails接口,所以,先将User类改成这样

@Data
public class User implements UserDetails{
    private String userId;
    private String account;
    private String password;



    @Override
    @JsonIgnore
    public String getPassword() {
        return password;
    }

    @Override
    @JsonIgnore
    public String getUsername() {
        return account;
    }
}

当然不要忘记 service

@Service
public class UserService implements AuthUserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        // 根据账号查询
        return null;
    }
}

应该记得,Spring Security是通过AuthenticationToken类的辨别该用什么Provider去执行登录逻辑。
默认的账号密码登录就是通过UsernamePasswordAuthenticationToken,执行DaoAuthenticationProvider完成登录。
所以,我们创建类UserUsernamePasswordAuthenticationToken,继承UsernamePasswordAuthenticationToken

public class UserUsernamePasswordAuthenticationToken extends UsernamePasswordAuthenticationToken {
    public UserUsernamePasswordAuthenticationToken(Object principal, Object credentials) {
        super(principal, credentials);
    }

    public UserUsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
        super(principal, credentials, authorities);
    }
}

这么做是为了跟接下来要做的管理员 账号密码登录做区分,避免两种账户的登录混淆了。

  1. 登录流程

完成前面的工作后,我们开始实现登录过程。
先定义User用的Provider

public class UserAuthenticationProvider extends DaoAuthenticationProvider {

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UserUsernamePasswordAuthenticationToken.class);
    }
}

登录成功的处理器

@Component
public class UserPasswordLoginSuccessHandler extends AbstractLoginSuccessHandler {

    @Resource
    private UserService userService;

    @Override
    public Object preAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) {
        User user = (User) authentication.getPrincipal();
		// do something 
        return userVO;
    }
}

别忘了 filter

public class PasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter{
    protected String username = null, password = null;
    private final Class<? extends UsernamePasswordAuthenticationToken> auth;



    public PasswordAuthenticationFilter(String loginPattern, Class<? extends UsernamePasswordAuthenticationToken> auth,
                                        AuthenticationSuccessHandler successHandler, AuthenticationFailureHandler failureHandler) {
        super(new AntPathRequestMatcher(loginPattern, "POST"));
        setSessionAuthenticationStrategy(new NullAuthenticatedSessionStrategy());
        this.auth = auth;
        this.setAuthenticationSuccessHandler(successHandler);
        this.setAuthenticationFailureHandler(failureHandler);
    }

    @Override
    public void afterPropertiesSet() {
        Assert.notNull(getAuthenticationManager(), "authenticationManager must be specified");
        Assert.notNull(getSuccessHandler(), "AuthenticationSuccessHandler must be specified");
        Assert.notNull(getFailureHandler(), "AuthenticationFailureHandler must be specified");
    }

    @SneakyThrows
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {
        super.preAuth(request);
        String body = StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8);
        // 获取参数中的账号密码
        if (StringUtils.hasText(body)) {
            JsonObject object = JSONUtils.parseObject(body);
            username = object.getString("account");
            password = object.getString("password");
        }
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = auth.getConstructor(Object.class, Object.class).newInstance(username, password);
        try {
            // 调用登录方法:provider
            return this.getAuthenticationManager().authenticate(usernamePasswordAuthenticationToken);
        } catch (BadCredentialsException b) {
            throw new BadCredentialsException("密码错误");
        } catch (LockedException l) {
            throw new BadCredentialsException("账号已被冻结");
        }
    }

}

此时的 配置代码如下:

@Configuration
@EnableWebSecurity// 这个注解必须加,开启Security
@EnableGlobalMethodSecurity(prePostEnabled = true)//保证post之前的注解可以使用
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;

  
    @Resource
    private UserService userService;

    @Resource
    private RestAuthenticationAccessDeniedHandler restAuthenticationAccessDeniedHandler;

    @Resource
    private TokenAuthenticationFailureHandler tokenAuthenticationFailureHandler;
 

    @Resource
    private LoginFailureHandler loginFailureHandler;

    @Resource
    private UserPasswordLoginSuccessHandler userPasswordLoginSuccessHandler;



    /**
     * Provider
     */

    public AuthenticationProvider userAuthentication() {
        DaoAuthenticationProvider provider = new UserAuthenticationProvider();
        provider.setUserDetailsService(userService);
        provider.setHideUserNotFoundExceptions(false);
        provider.setPasswordEncoder(bCryptPasswordEncoder);
        return provider;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) {

        auth.authenticationProvider(userAuthentication());

    }
	// 过滤器
    protected List<AbstractAuthenticationProcessingFilter> configFilters() {
        List<AbstractAuthenticationProcessingFilter> filters = new ArrayList<>();
        filters.add(new PasswordAuthenticationFilter("/user/login/account", UserUsernamePasswordAuthenticationToken.class, userPasswordLoginSuccessHandler, loginFailureHandler));
        return filters;
    }

    @Override
    public void configure(WebSecurity web) {
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling()
                .authenticationEntryPoint(new MyAuthenticationEntryPoint())
                .accessDeniedHandler(restAuthenticationAccessDeniedHandler)
                .and()
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .csrf().disable()
                .formLogin().disable()
                .sessionManagement().disable()
                .cors()
                .and()
                .headers().addHeaderWriter(new StaticHeadersWriter(Arrays.asList(new Header("Access-control-Allow-Origin", "*"), new Header("Access-Control-Expose-Headers", "generateAuthorization"))))
                .and()
                .addFilterAfter(new OptionsRequestFilter(), CorsFilter.class)
                //配置token认证
                .apply(new JwtAuthorizeConfigurer<>())
                .addJwtAuthenticationFilter(JwtAuthenticationFilter.create("/user/**", UserJwtAuthenticationToken.class, null, tokenAuthenticationFailureHandler,
                        "/user/login/account"))
                //配置登陆
                .and()
                .apply(new LoginConfigurer<>(configFilters()))
                .and()
        ;
    }
}

至此完成了User账号密码登录配置。

先定义User用的Provider

public class UserAuthenticationProvider extends DaoAuthenticationProvider {

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UserUsernamePasswordAuthenticationToken.class);
    }
}

登录成功的处理器

@Component
public class UserPasswordLoginSuccessHandler extends AbstractLoginSuccessHandler {

    @Resource
    private UserService userService;

    @Override
    public Object preAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) {
        User user = (User) authentication.getPrincipal();
		// do something 
        return userVO;
    }
}

别忘了 filter

public class PasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter{
    protected String username = null, password = null;
    private final Class<? extends UsernamePasswordAuthenticationToken> auth;



    public PasswordAuthenticationFilter(String loginPattern, Class<? extends UsernamePasswordAuthenticationToken> auth,
                                        AuthenticationSuccessHandler successHandler, AuthenticationFailureHandler failureHandler) {
        super(new AntPathRequestMatcher(loginPattern, "POST"));
        setSessionAuthenticationStrategy(new NullAuthenticatedSessionStrategy());
        this.auth = auth;
        this.setAuthenticationSuccessHandler(successHandler);
        this.setAuthenticationFailureHandler(failureHandler);
    }

    @Override
    public void afterPropertiesSet() {
        Assert.notNull(getAuthenticationManager(), "authenticationManager must be specified");
        Assert.notNull(getSuccessHandler(), "AuthenticationSuccessHandler must be specified");
        Assert.notNull(getFailureHandler(), "AuthenticationFailureHandler must be specified");
    }

    @SneakyThrows
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {
        super.preAuth(request);
        String body = StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8);
        // 获取参数中的账号密码
        if (StringUtils.hasText(body)) {
            JsonObject object = JSONUtils.parseObject(body);
            username = object.getString("account");
            password = object.getString("password");
        }
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = auth.getConstructor(Object.class, Object.class).newInstance(username, password);
        try {
            // 调用登录方法:provider
            return this.getAuthenticationManager().authenticate(usernamePasswordAuthenticationToken);
        } catch (BadCredentialsException b) {
            throw new BadCredentialsException("密码错误");
        } catch (LockedException l) {
            throw new BadCredentialsException("账号已被冻结");
        }
    }

}

此时的 配置代码如下:

@Configuration
@EnableWebSecurity// 这个注解必须加,开启Security
@EnableGlobalMethodSecurity(prePostEnabled = true)//保证post之前的注解可以使用
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;

  
    @Resource
    private UserService userService;

    @Resource
    private RestAuthenticationAccessDeniedHandler restAuthenticationAccessDeniedHandler;

    @Resource
    private TokenAuthenticationFailureHandler tokenAuthenticationFailureHandler;
 

    @Resource
    private LoginFailureHandler loginFailureHandler;

    @Resource
    private UserPasswordLoginSuccessHandler userPasswordLoginSuccessHandler;



    /**
     * Provider
     */

    public AuthenticationProvider userAuthentication() {
        DaoAuthenticationProvider provider = new UserAuthenticationProvider();
        provider.setUserDetailsService(userService);
        provider.setHideUserNotFoundExceptions(false);
        provider.setPasswordEncoder(bCryptPasswordEncoder);
        return provider;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) {

        auth.authenticationProvider(userAuthentication());

    }
	// 过滤器
    protected List<AbstractAuthenticationProcessingFilter> configFilters() {
        List<AbstractAuthenticationProcessingFilter> filters = new ArrayList<>();
        filters.add(new PasswordAuthenticationFilter("/user/login/account", UserUsernamePasswordAuthenticationToken.class, userPasswordLoginSuccessHandler, loginFailureHandler));
        return filters;
    }

    @Override
    public void configure(WebSecurity web) {
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling()
                .authenticationEntryPoint(new MyAuthenticationEntryPoint())
                .accessDeniedHandler(restAuthenticationAccessDeniedHandler)
                .and()
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .csrf().disable()
                .formLogin().disable()
                .sessionManagement().disable()
                .cors()
                .and()
                .headers().addHeaderWriter(new StaticHeadersWriter(Arrays.asList(new Header("Access-control-Allow-Origin", "*"), new Header("Access-Control-Expose-Headers", "generateAuthorization"))))
                .and()
                .addFilterAfter(new OptionsRequestFilter(), CorsFilter.class)
                //配置token认证
                .apply(new JwtAuthorizeConfigurer<>())
                .addJwtAuthenticationFilter(JwtAuthenticationFilter.create("/user/**", UserJwtAuthenticationToken.class, null, tokenAuthenticationFailureHandler,
                        "/user/login/account"))
                //配置登陆
                .and()
                .apply(new LoginConfigurer<>(configFilters()))
                .and()
        ;
    }
}

至此完成了User账号密码登录配置。

多账号模式

账号2

我们创建一个新的账号类Admin

  1. 定义一个Admin类:
@Data
public class Admin {
    private String adminId;
    private String account;
    private String password;
}

其他步骤省略,创建类AdminUsernamePasswordAuthenticationToken,继承UsernamePasswordAuthenticationToken

public class AdminUsernamePasswordAuthenticationToken extends UsernamePasswordAuthenticationToken {
    public AdminUsernamePasswordAuthenticationToken(Object principal, Object credentials) {
        super(principal, credentials);
    }

    public AdminUsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
        super(principal, credentials, authorities);
    }
}
  1. 登录流程

Admin用的Provider

public class AdminAuthenticationProvider extends DaoAuthenticationProvider {

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(AdminUsernamePasswordAuthenticationToken.class);
    }
}

注意supports方法里的参数

登录成功的处理器

@Component
public class AdminPasswordLoginSuccessHandler extends AbstractLoginSuccessHandler {
    @Resource
    private AdminService adminService;

    @Override
    public Object preAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) {
        Admin admin = (Admin) authentication.getPrincipal();
        return admin;
    }
}

此时的 配置代码如下:

@Configuration
@EnableWebSecurity// 这个注解必须加,开启Security
@EnableGlobalMethodSecurity(prePostEnabled = true)//保证post之前的注解可以使用
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;

  
    @Resource
    private UserService userService;

    @Resource
    private RestAuthenticationAccessDeniedHandler restAuthenticationAccessDeniedHandler;

    @Resource
    private TokenAuthenticationFailureHandler tokenAuthenticationFailureHandler;
 

    @Resource
    private LoginFailureHandler loginFailureHandler;

    @Resource
    private UserPasswordLoginSuccessHandler userPasswordLoginSuccessHandler;



    /**
     * Provider
     */

    public AuthenticationProvider userAuthentication() {
        DaoAuthenticationProvider provider = new UserAuthenticationProvider();
        provider.setUserDetailsService(userService);
        provider.setHideUserNotFoundExceptions(false);
        provider.setPasswordEncoder(bCryptPasswordEncoder);
        return provider;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) {

        auth.authenticationProvider(userAuthentication());

    }
	// 过滤器
    protected List<AbstractAuthenticationProcessingFilter> configFilters() {
        List<AbstractAuthenticationProcessingFilter> filters = new ArrayList<>();
        filters.add(new PasswordAuthenticationFilter("/user/login/account", UserUsernamePasswordAuthenticationToken.class, userPasswordLoginSuccessHandler, loginFailureHandler));
        return filters;
    }

    @Override
    public void configure(WebSecurity web) {
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling()
                .authenticationEntryPoint(new MyAuthenticationEntryPoint())
                .accessDeniedHandler(restAuthenticationAccessDeniedHandler)
                .and()
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .csrf().disable()
                .formLogin().disable()
                .sessionManagement().disable()
                .cors()
                .and()
                .headers().addHeaderWriter(new StaticHeadersWriter(Arrays.asList(new Header("Access-control-Allow-Origin", "*"), new Header("Access-Control-Expose-Headers", "generateAuthorization"))))
                .and()
                .addFilterAfter(new OptionsRequestFilter(), CorsFilter.class)
                //配置token认证
                .apply(new JwtAuthorizeConfigurer<>())
                .addJwtAuthenticationFilter(JwtAuthenticationFilter.create("/user/**", UserJwtAuthenticationToken.class, null, tokenAuthenticationFailureHandler,
                        "/user/login/account"))
                //配置登陆
                .and()
                .apply(new LoginConfigurer<>(configFilters()))
                .and()
        ;
    }
}

至此完成了User账号密码登录配置。

先定义User用的Provider

public class UserAuthenticationProvider extends DaoAuthenticationProvider {

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UserUsernamePasswordAuthenticationToken.class);
    }
}

登录成功的处理器

@Component
public class UserPasswordLoginSuccessHandler extends AbstractLoginSuccessHandler {

    @Resource
    private UserService userService;

    @Override
    public Object preAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) {
        User user = (User) authentication.getPrincipal();
		// do something 
        return userVO;
    }
}

别忘了 filter

public class PasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter{
    protected String username = null, password = null;
    private final Class<? extends UsernamePasswordAuthenticationToken> auth;



    public PasswordAuthenticationFilter(String loginPattern, Class<? extends UsernamePasswordAuthenticationToken> auth,
                                        AuthenticationSuccessHandler successHandler, AuthenticationFailureHandler failureHandler) {
        super(new AntPathRequestMatcher(loginPattern, "POST"));
        setSessionAuthenticationStrategy(new NullAuthenticatedSessionStrategy());
        this.auth = auth;
        this.setAuthenticationSuccessHandler(successHandler);
        this.setAuthenticationFailureHandler(failureHandler);
    }

    @Override
    public void afterPropertiesSet() {
        Assert.notNull(getAuthenticationManager(), "authenticationManager must be specified");
        Assert.notNull(getSuccessHandler(), "AuthenticationSuccessHandler must be specified");
        Assert.notNull(getFailureHandler(), "AuthenticationFailureHandler must be specified");
    }

    @SneakyThrows
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {
        super.preAuth(request);
        String body = StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8);
        // 获取参数中的账号密码
        if (StringUtils.hasText(body)) {
            JsonObject object = JSONUtils.parseObject(body);
            username = object.getString("account");
            password = object.getString("password");
        }
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = auth.getConstructor(Object.class, Object.class).newInstance(username, password);
        try {
            // 调用登录方法:provider
            return this.getAuthenticationManager().authenticate(usernamePasswordAuthenticationToken);
        } catch (BadCredentialsException b) {
            throw new BadCredentialsException("密码错误");
        } catch (LockedException l) {
            throw new BadCredentialsException("账号已被冻结");
        }
    }

}

此时的 配置代码如下:


@Configuration
@EnableWebSecurity// 这个注解必须加,开启Security
@EnableGlobalMethodSecurity(prePostEnabled = true)//保证post之前的注解可以使用
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Resource
    private AdminService adminService;

    @Resource
    private UserService userService;

    @Resource
    private RestAuthenticationAccessDeniedHandler restAuthenticationAccessDeniedHandler;

    @Resource
    private TokenAuthenticationFailureHandler tokenAuthenticationFailureHandler;
    /**
     * Handler
     */

    @Resource
    private LoginFailureHandler loginFailureHandler;


    @Resource
    private AdminPasswordLoginSuccessHandler adminPasswordLoginSuccessHandler;


    @Resource
    private UserPasswordLoginSuccessHandler userPasswordLoginSuccessHandler;


    /**
     * Provider
     */


    public AuthenticationProvider adminAuthentication() {
        DaoAuthenticationProvider provider = new AdminAuthenticationProvider();
        provider.setUserDetailsService(adminService);
        provider.setHideUserNotFoundExceptions(false);
        provider.setPasswordEncoder(bCryptPasswordEncoder);
        return provider;
    }

    public AuthenticationProvider userAuthentication() {
        DaoAuthenticationProvider provider = new UserAuthenticationProvider();
        provider.setUserDetailsService(userService);
        provider.setHideUserNotFoundExceptions(false);
        provider.setPasswordEncoder(bCryptPasswordEncoder);
        return provider;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) {

        auth
                .authenticationProvider(adminAuthentication())
                .authenticationProvider(userAuthentication())
        ;

    }
	// 登录过滤器链
    protected List<AbstractAuthenticationProcessingFilter> configFilters() {
        List<AbstractAuthenticationProcessingFilter> filters = new ArrayList<>();
        filters.add(new PasswordAuthenticationFilter("/admin/login/account", AdminUsernamePasswordAuthenticationToken.class, adminPasswordLoginSuccessHandler, loginFailureHandler));
        filters.add(new PasswordAuthenticationFilter("/user/login/account", UserUsernamePasswordAuthenticationToken.class, userPasswordLoginSuccessHandler, loginFailureHandler));
        return filters;
    }

    @Override
    public void configure(WebSecurity web) {
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling()
                .authenticationEntryPoint(new MyAuthenticationEntryPoint())
                .accessDeniedHandler(restAuthenticationAccessDeniedHandler)
                .and()
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .csrf().disable()
                .formLogin().disable()
                .sessionManagement().disable()
                .cors()
                .and()
                .headers().addHeaderWriter(new StaticHeadersWriter(Arrays.asList(new Header("Access-control-Allow-Origin", "*"), new Header("Access-Control-Expose-Headers", "generateAuthorization"))))
                .and()
                .addFilterAfter(new OptionsRequestFilter(), CorsFilter.class)
                //配置token认证
                .apply(new JwtAuthorizeConfigurer<>())
                .addJwtAuthenticationFilter(JwtAuthenticationFilter.create("/admin/**", AdminJwtAuthenticationToken.class, null, tokenAuthenticationFailureHandler,
                        "/admin/login/account"))
                .addJwtAuthenticationFilter(JwtAuthenticationFilter.create("/user/**", UserJwtAuthenticationToken.class, null, tokenAuthenticationFailureHandler,
                        "/user/login/account"))
                //配置登陆
                .and()
                .apply(new LoginConfigurer<>(configFilters()))
                .and()
        ;
    }
}

至此,我们完成了双账号的账号密码登录模式。

简单总结

spring security是通过token类控制登录流程的,因此 不管有多少个账号类,只要每个账号都有对应的一个token类,并且有对应的provider(实际上并不需要,但账号密码登录我们目前使用spring security的方法,因此才需要)、successHandler 即可。

登录方式扩展

未完待续…

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值