SpringBoot 整合security 实现自定义Token

2021-06-09  本文已影响0人  猫的树

接上一篇
6.认证相关处理创建
登录成功 DemoAuthenticationSuccessHandler.java

/**
 * 用户身份验证通过处理
 */
@Component
@SuppressWarnings("all")
public class DemoAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    @Autowired
    private TokenService tokenService;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest,
                                        HttpServletResponse httpServletResponse,
                                        Authentication authentication) throws IOException, ServletException {
        // 取得认证用户信息
        UserDetailsInfo userInfo = (UserDetailsInfo) authentication.getDetails();

        // 设置用户返回信息
        UserInfoOutputDto outputDto = new UserInfoOutputDto();
        String username = userInfo.getUsername();
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        outputDto.setRole(userInfo.getRole());
        outputDto.setLoginTime(dateFormat.format(date));
        outputDto.setUserId(userInfo.getUserId());
        outputDto.setUserName(userInfo.getUsername());

        // 创建Token
        userInfo.setIp(ClientIdUtil.getIp(httpServletRequest));
        TokenInfo tokenInfo = tokenService.createToken(userInfo);

        outputDto.setClientId(tokenInfo.getClientId());
        outputDto.setAccessToken(tokenInfo.getAccessToken());
        ResultData data = new ResultData(1, "login successful", outputDto);
        Gson gson = new Gson();
        httpServletResponse.getWriter().write(gson.toJson(data));
    }
}

UserInfoOutputDto.java

/**
 * 用户登录返回信息
 */
public class UserInfoOutputDto {
    private String userId;
    private String userName;
    private String role;
    private String clientId;
    private String accessToken;
    private String loginTime;
    ...

登录失败 DemoAuthenticationFailureHandler.java

/**
 * 用户身份验证失败处理
 */
@Component
public class DemoAuthenticationFailureHandler implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest,
                                        HttpServletResponse httpServletResponse,
                                        AuthenticationException e) throws IOException, ServletException {
        PermissionJsonException jsonException = new PermissionJsonException();
        if (e instanceof UsernameNotFoundException) {
            jsonException.setCode(10001);
            jsonException.setMsg("username not exits");
        } else if (e instanceof BadCredentialsException) {
            jsonException.setCode(10002);
            jsonException.setMsg("wrong password ");
        } else if (e instanceof DisabledException) {
            jsonException.setCode(10003);
            jsonException.setMsg("user is disabled");
        } else {
            jsonException.setCode(10004);
            jsonException.setMsg("error");
        }
        httpServletResponse.setContentType("application/json;charset=UTF-8");
        Gson gson = new Gson();
        httpServletResponse.getWriter().write(gson.toJson(jsonException));
    }
}

账号同时登录处理 DemoExpiredHandler.java

/**
 * 账号同时登录处理
 */
@Component
@SuppressWarnings("all")
public class DemoExpiredHandler implements SessionInformationExpiredStrategy {

    @Autowired
    private TokenService tokenService;

    @Override
    public void onExpiredSessionDetected(SessionInformationExpiredEvent
                                             sessionInformationExpiredEvent) throws IOException, ServletException {
        // 获取登录的token信息
        String clientId = sessionInformationExpiredEvent.getRequest().getHeader("clientId");
        TokenInfo tokenInfo = tokenService.findByClientId(clientId);
        // 设置账户登录信息
        ExpiredData expiredData = new ExpiredData();
        // 登录ip
        expiredData.setIp(tokenInfo.getIp());
        SimpleDateFormat dateFormat = new SimpleDateFormat("MM-dd HH:mm");
        // 登录时间
        expiredData.setLoginTime(dateFormat.format(tokenInfo.getUpdateTime()));
        Gson gson = new Gson();
        sessionInformationExpiredEvent.getResponse().getWriter().write(gson.toJson(expiredData));
    }
}

ExpiredData.java

/**
 * 重复登录信息
 */
public class ExpiredData {
    /**
     * 登录ip
     */
    private String ip;
    /**
     * 登录时间
     */
    private String loginTime;

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public String getLoginTime() {
        return loginTime;
    }

    public void setLoginTime(String loginTime) {
        this.loginTime = loginTime;
    }
}

重点来了

7.Security配置

package com.example.demo.base.config;

import com.example.demo.base.common.DemoAuthenticationFailureHandler;
import com.example.demo.base.common.DemoAuthenticationProvider;
import com.example.demo.base.common.DemoAuthenticationSuccessHandler;
import com.example.demo.base.common.DemoExpiredHandler;
import com.example.demo.base.common.DemoLogoutSuccessHandler;
import com.example.demo.base.filter.SecurityFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;

/**
 * Security配置
 */
@Configuration
@SuppressWarnings("all")
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private DemoAuthenticationProvider demoAuthenticationProvider;
    @Autowired
    private DemoAuthenticationFailureHandler failureHandler;
    @Autowired
    private DemoAuthenticationSuccessHandler successHandler;
    @Autowired
    private DemoLogoutSuccessHandler logoutSuccessHandler;
    @Autowired
    private DemoExpiredHandler expiredHandler;

    /**
     * 验证用户密码
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(demoAuthenticationProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests()
            .antMatchers("/favicon.ico").permitAll()
            // 请求需要身份认证
            .anyRequest().authenticated()
            // 配置登录页面
            .and().formLogin()
            .loginPage("/nopermission")
            // 登录请求url
            .loginProcessingUrl("/login")
            // 身份验证成功/失败 处理
            .successHandler(successHandler).failureHandler(failureHandler).permitAll()
            // 退出登录处理
            .and().logout().logoutUrl("/logout")
            .logoutSuccessHandler(logoutSuccessHandler)
            .deleteCookies("JSESSIONID")
            .and().addFilterAt(securityFilter(), FilterSecurityInterceptor.class).exceptionHandling()
            // 相同账号的最大用户数
            .and().sessionManagement().maximumSessions(1)
            .expiredSessionStrategy(expiredHandler);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/static/**");
    }

    @Bean
    SecurityFilter securityFilter() {
        return new SecurityFilter();
        // 这个方法才能在拦截器中自动注入查询数据库的对象
    }

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

代码写到这,一个实现Token验证的登录就写好了,下一篇我们可以测试一下是否成功。

上一篇下一篇

猜你喜欢

热点阅读