sprintboot+spring security +jwt 实现登录

直接上代码吧

1.maven依赖

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

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

2.security配置类 继承WebSecurityConfigurerAdapter

package cn.likui.study.config;

import cn.likui.study.auth.JwtAuthenticationEntryPoint;
import cn.likui.study.filters.JwtTokenFilter;
import cn.likui.study.service.impl.SysUserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
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.method.configuration.EnableGlobalMethodSecurity;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
* @Description: security配置类,配置权限相关密码.
* @Author: ldg
* @Date: 2020/10/14
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 调用失败的节点配置.
     */
    @Autowired
    private JwtAuthenticationEntryPoint unauthorizedHandler;
    /**
     * 权限不够的处理对象.
     */
    @Autowired
    private AccessDeniedHandler accessDeniedHandler;
    /**
     * 获取自定义用户类.
     */
    @Autowired
    private SysUserDetailsServiceImpl sysUserDetailsService;
    /**
     * 网关拦截,获取Token
     */
    @Autowired
    private JwtTokenFilter authenticationTokenFilter;

    @Value("${spring.login.url}")
    private String loginUrl;

    @Value("${spring.logout.url}")
    private String logoutUrl;

    @Value("${spring.create.url}")
    private String createUrl;

    @Value("${spring.find.url}")
    private String findUrl;


    /**
     * 装载BCrypt密码编码器
     *
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 构造函数.
     * @param unauthorizedHandler
     * @param accessDeniedHandler
     * @param sysUserDetailsService
     * @param authenticationTokenFilter
     */
    @Autowired
    public SecurityConfig(JwtAuthenticationEntryPoint unauthorizedHandler,
                          JwtTokenFilter authenticationTokenFilter,
                          @Qualifier("SysAccessDeniedHandler") AccessDeniedHandler accessDeniedHandler,
                          @Qualifier("SysUserDetailsService") SysUserDetailsServiceImpl sysUserDetailsService
                          ) {
        this.unauthorizedHandler = unauthorizedHandler;
        this.accessDeniedHandler = accessDeniedHandler;
        this.sysUserDetailsService = sysUserDetailsService;
        this.authenticationTokenFilter = authenticationTokenFilter;
    }

    /**
     * 验证身份相关配置.
     *
     * @param authenticationManagerBuilder
     * @throws Exception
     */
    @Autowired
    public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder
                // 设置UserDetailsService
                .userDetailsService(this.sysUserDetailsService)
                // 使用BCrypt进行密码的hash
                .passwordEncoder(passwordEncoder());
    }

    /**
     * 设置过滤条件配置.
     *
     * @param httpSecurity
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        //set configuration.
        httpSecurity
                .exceptionHandling().accessDeniedHandler(accessDeniedHandler).and()
                // 由于使用的是JWT,我们这里不需要csrf.
                .csrf().disable()
                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
                // 基于token,所以不需要session.
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                // 对于获取token的rest api要允许匿名访问.
                .antMatchers(
                        loginUrl,
                        logoutUrl,
                        createUrl,
                        "/stomp/**",
                        "/test/**",
                        "/workflow/**",
                        "/blockchain/**",
                        "/error/**").permitAll()
                // 除上面外的所有请求全部需要鉴权认证
                .anyRequest().authenticated();
        // 禁用缓存
        httpSecurity.headers().cacheControl();
        // 添加JWT filter
        httpSecurity
                .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
                //权限不足filter.
                .exceptionHandling().accessDeniedHandler(accessDeniedHandler)
                //异常处理endpoint.
                .authenticationEntryPoint(unauthorizedHandler);
    }

    /**
     * 设置过滤web过滤.
     * @param web
     */
    @Override
    public void configure(WebSecurity web) {
        web.ignoring().antMatchers(
           "swagger-ui.html",
                        "**/swagger-ui.html",
                        "/favicon.ico",
                        "/**/*.css",
                        "/**/*.js",
                        "/**/*.png",
                        "/**/*.gif",
                        "/swagger-resources/**",
                        "/v2/**",
                        "/**/*.ttf");
        web.ignoring().antMatchers("/v2/api-docs",
                        "/swagger-resources/configuration/ui",
                        "/swagger-resources",
                        "/swagger-resources/configuration/security",
                        "/swagger-ui.html");
    }

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

3.调用失败的节点配置

package cn.likui.study.auth;

import cn.likui.study.entity.CodeType;
import cn.likui.study.entity.ResponseMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Serializable;

/**
* @Description: 认证失败之后调用的接口.验证为未登陆状态会进入此方法,认证错误.
* @Author: ldg
* @Date: 2020/10/14
*/
@Slf4j
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {
    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                         AuthenticationException e) throws IOException {

        log.info("EntryPoint");
        log.info("认证失败:{}", e.getMessage());
        log.info("请求URI: {}", httpServletRequest.getRequestURI());

        httpServletResponse.setStatus(200);
        httpServletResponse.setCharacterEncoding("UTF-8");
        httpServletResponse.setContentType("application/json; charset=utf-8");

        PrintWriter printWriter = httpServletResponse.getWriter();
        ResponseMessage<?> message = ResponseMessage.error(CodeType.TOKEN_UNAUTHORIZED);
        String body = message.toJson();
        printWriter.write(body);
        printWriter.flush();
    }
}

4.权限不够的处理对象

package cn.likui.study.auth;

import cn.likui.study.entity.CodeType;
import cn.likui.study.entity.ResponseMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
* @Description: 权限不够调用的接口.
* @Author: ldg
* @Date: 2020/10/14
*/
@Slf4j
@Component("SysAccessDeniedHandler")
public class SysAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
        //登陆状态下,权限不足执行该方法
        log.info("权限不足:" + e.getMessage());
        response.setStatus(200);
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter printWriter = response.getWriter();
        ResponseMessage<?> message = ResponseMessage.error(CodeType.TOKEN_FORBIDDEN.getCode(), e.getMessage());
        String body = message.toJson();
        printWriter.write(body);
        printWriter.flush();
    }
}

5.网关拦截,获取Token

package cn.likui.study.filters;

import cn.likui.study.entity.CodeType;
import cn.likui.study.entity.ResponseMessage;
import cn.likui.study.entity.SysUserDetail;
import cn.likui.study.utils.JwtUtil;
import com.github.pagehelper.util.StringUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
* @Description:
 * * 拦截器直接拦截请求,失败之后跳转到JWTAuthenticationEntryPoint类.
 *  * 1
 *  * token校验
* @Author: ldg
* @Date: 2020/10/14
*/
@Slf4j
@Component
public class JwtTokenFilter extends OncePerRequestFilter {

    private static final String CLAIM_KEY_USER_ID = "user_id";
    private static final String CLAIM_KEY_USER_NAME = "user_name";

    @Value("${jwt.header}")
    private String token_header;
    @Value("${jwt.tokenHead}")
    private String safe_header;

    //处理options浏览器请求.
    private boolean optionsProc(HttpServletRequest request, HttpServletResponse response){
        if (RequestMethod.OPTIONS.name().equals(request.getMethod())) {   //判断如果是复杂请求,直接返回200.
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "POST,GET,PUT,OPTIONS,DELETE");
            response.setHeader("Access-Control-Max-Age", "3600");
            //下面这句话很重要.
            response.setHeader("Access-Control-Allow-Headers", "Origin,X-Requested-With,Content-Type,Accept,Authorization,token");
            //设置好之后,不走spring security后续链路.
            return true;
        }
        return false;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        if (optionsProc(request, response)) {
            return;
        }
        String auth_token = request.getHeader(this.token_header);
        //前缀.
        final String auth_token_start = safe_header;
        //判断token
        if (!StringUtils.isEmpty(auth_token) && auth_token.startsWith(auth_token_start)) {
            auth_token = auth_token.substring(auth_token_start.length());
        } else {
            // 不按规范,不允许通过验证
            auth_token = null;
        }
        Claims claims = null;
        try {
            claims = JwtUtil.parseJwt(auth_token);
        } catch (ExpiredJwtException jwtException) {
            sendFailedMessage(response, CodeType.TOKEN_EXPIRED);
            return;
        } catch (Exception e) {
            chain.doFilter(request, response);
            return;
        }
        //没有获取到用户信息.
        if (claims != null && !JwtUtil.isTokenTimeout(claims) && SecurityContextHolder.getContext().getAuthentication() == null) {
            log.info("Checking authentication for issuer {}.", claims.getIssuer());
            SysUserDetail userDetail = getUserFromToken(auth_token);
            //这里需要判断userDetail中的用户是否在登陆中.等等.
            if (userDetail != null && null != (userDetail.getId())
                    && !StringUtil.isEmpty(userDetail.getUsername())) {
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetail, null, userDetail.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                logger.info(String.format("Authenticated userDetail %s, setting security context", userDetail.getUsername()));
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        }
        chain.doFilter(request, response);
    }


    /**
     * 通过token返回UserDetail
     *
     * @param token
     * @return
     */
    public SysUserDetail getUserFromToken(String token) {
        SysUserDetail userDetail;
        try {
            Claims claims = JwtUtil.parseJwt(token);
            String userId = claims.get(CLAIM_KEY_USER_ID).toString();
            Object obj = claims.get(CLAIM_KEY_USER_NAME);
            String username = "";
            if(obj != null){
                username = obj.toString();
            }
            userDetail = new SysUserDetail(Integer.valueOf(userId), username, token);
        } catch (Exception e) {
            userDetail = null;
        }
        return userDetail;
    }


    private void sendFailedMessage(HttpServletResponse response, CodeType codeType) {
        response.setStatus(200);
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        try {
            PrintWriter printWriter = response.getWriter();
            ResponseMessage<?> message = ResponseMessage.error(codeType.getCode(), codeType.getDescription());
            log.error("code:{},message:{}", codeType.getCode(), codeType.getDescription());
            String body = message.toJson();
            printWriter.write(body);
            printWriter.flush();
        } catch (IOException ioe) {
            log.error(ioe.getMessage());
        }
    }
}

6.异常类

package cn.likui.study.exception;

import cn.likui.study.entity.ResponseMessage;

/**
 * dssp security exception
 */
public class SysSecurityException extends RuntimeException{
    private ResponseMessage message;

    public SysSecurityException(ResponseMessage message){
        this.message = message;
    }

    @Override
    public String getMessage() {
        return message.getMessage();
    }
}

7.请求响应类

package cn.likui.study.entity;

import com.alibaba.fastjson.JSON;
import lombok.NoArgsConstructor;
import java.io.Serializable;

/**
 * @param <T> T:响应体数据类型
 * @author
 * 请求响应类
 */
@NoArgsConstructor
public class ResponseMessage<T> implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 状态码
     */
    private Integer code;

    /**
     * 异常信息
     */
    private String message;

    /**
     * 响应信息
     */
    private T data;

    private boolean error = false;

    /**
     * 是否错误.
     *
     * @return
     */
    public boolean isError() {
        return error;
    }

    /**
     * 构造成功消息
     *
     * @param <T> 返回数据类型
     * @return 消息
     */
    public static <T> ResponseMessage<T> success() {
        ResponseMessage msg = new ResponseMessage<T>(CodeType.SUCCESS.getCode(), CodeType.SUCCESS.getDescription(), null);
        msg.error = false;
        return msg;
    }

    public static <T> ResponseMessage<T> success(String message) {
        ResponseMessage msg = new ResponseMessage<T>(CodeType.SUCCESS.getCode(), message, null);
        msg.error = false;
        return msg;
    }

    /**
     * 构造成功消息
     *
     * @param data 返回数据
     * @param <T>  返回数据类型
     * @return 消息
     */
    public static <T> ResponseMessage<T> success(T data) {
        ResponseMessage msg = new ResponseMessage<T>(CodeType.SUCCESS.getCode(), null, data);
        msg.error = false;
        return msg;
    }

    /**
     * 构造错误消息
     *
     * @param errorCode    异常状态码
     * @param errorMessage 异常描述信息
     * @return 消息
     */
    public static ResponseMessage<?> error(Integer errorCode, String errorMessage) {
        ResponseMessage msg = new ResponseMessage(errorCode, errorMessage, null);
        msg.error = true;
        return msg;
    }

    public static ResponseMessage<?> error(CodeType type) {
        ResponseMessage msg = new ResponseMessage(type.getCode(), type.getDescription(), null);
        msg.error = true;
        return msg;
    }

    public static ResponseMessage<?> error(CodeType type, String errorMessage) {
        ResponseMessage msg = new ResponseMessage(type.getCode(), errorMessage, null);
        msg.error = true;
        return msg;
    }

    /**
     * to json.
     *
     * @return
     */
    public String toJson() {
        return this == null ? "" : JSON.toJSONString(this);
    }


    /**
     * 私有构造器
     *
     * @param code    状态码
     * @param message 状态描述
     * @param data    数据
     */
    private ResponseMessage(Integer code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
        this.error = false;
    }

    public ResponseMessage(CodeType codeType, T data, boolean isError) {
        this.code = codeType.getCode();
        this.message = codeType.getDescription();
        this.data = data;
        this.error = isError;
    }

    /**
     * 获取状态码
     *
     * @return 状态码
     */
    public Integer getCode() {
        return code;
    }

    /**
     * 获取异常描述信息
     *
     * @return 异常描述信息
     */
    public String getMessage() {
        return message;
    }

    /**
     * 获取返回数据
     *
     * @return 返回数据
     */
    public T getData() {
        return data;
    }


}

9.枚举

package cn.likui.study.entity;

/**
 * 异常代码描述。
 * @author
 */
public enum CodeType {


    //参数
    UNKNOWN_ERROR(1000, "未知错误"),
    
    TOKEN_EXPIRED(2000, "Token过期"),
    TOKEN_EXCEPTION(2001, "Token异常"),
    TOKEN_BLACLIST(2002, "当前用户已列入黑名单"),
    TOKEN_REGISTERED(2003, "当前用户已经注册"),
    TOKEN_REGISTER_FAIL(2004, "用户注册失败"),
    TOKEN_UNAUTHORIZED(2005, "认证失败"),
    TOKEN_FORBIDDEN(2006, "权限不足"),
    TOKEN_PARAMETER_ERROR(2007, "参数错误"),
    ERROR_LOGIN_EMAIL(2008, "用户邮箱未注册"),
    

    /**
     * 错误编码
     */
    private Integer code;
    /**
     * 错误描述
     */
    private String description;

    private CodeType(Integer code, String description) {
        this.code = code;
        this.description = description;
    }

    /**
     * 根据错误编码实例
     *
     * @param code 错误编码
     * @return 实例
     */
    public static CodeType getErrorCode(Integer code) {
        for (CodeType errorCode : CodeType.values()) {
            if (errorCode.getCode().equals(code)) {
                return errorCode;
            }
        }
        return CodeType.UNKNOWN_ERROR;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

10.入参对象

/**
* @Description:
* @Author: ldg
* @Date: 2020/10/15
*/
@Data
public class LoginEntity {
    private String loginEmail;
    private String phone;
    private String oldPassword;
    private String password;
}

11.控制层登录方法注册方法

package cn.likui.study.controller;

import cn.likui.study.entity.CodeType;
import cn.likui.study.entity.LoginEntity;
import cn.likui.study.entity.ResponseMessage;
import cn.likui.study.entity.SysUserDetail;
import cn.likui.study.mapper.SysUserMapper;
import cn.likui.study.service.AuthService;
import cn.likui.study.utils.JwtUtil;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 权限认证controller
 *
 * @author
 */
@Slf4j
@RestController
@RequestMapping("/gateway")
public class AuthController {

    @Value("${jwt.header}")
    private String strTokenHeader;

    @Value("${jwt.tokenHead}")
    private String safe_header;

    private final String HEADER_AUTHORIZATION = "Authorization";

    @Autowired
    AuthService service;
//    @Resource
//    SysUserMapper mapper;

    /**
     * 修改密码.
     * @param loginEntity
     * @return
     */
    @PostMapping("/changePassword")
    public ResponseMessage changePassword(@RequestBody LoginEntity loginEntity) {

        ResponseMessage msg = null;

        //用户名(手机或者邮箱),新密码,旧密码.
        if (null == loginEntity
                || StringUtils.isBlank(loginEntity.getOldPassword())
                || StringUtils.isBlank(loginEntity.getPassword()) ) {
            return ResponseMessage.error(CodeType.MISSING_PARAME);
        } else {
            if (StringUtils.isBlank(loginEntity.getPhone()) && StringUtils.isBlank(loginEntity.getLoginEmail()) ) {
                return ResponseMessage.error(CodeType.MISSING_PARAME);
            }
        }

        String userName = StringUtil.isNotEmpty(loginEntity.getLoginEmail()) ? loginEntity.getLoginEmail() : loginEntity.getPhone();
        try {
            SysUserDetail userDetail = service.login(userName, loginEntity.getOldPassword());
            msg = verifyDsspUserDetail(userDetail);
            if(!msg.isError()){
                BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
                String encode = encoder.encode(loginEntity.getPassword());
                Integer state = 1;
//                Integer state = mapper.updatePassword(loginEntity.getLoginEmail(), loginEntity.getPhone(), encode);
                if (state > 0) {
                    return ResponseMessage.success();
                } else {
                    return ResponseMessage.error(CodeType.CHANGE_PASSWORD_ERROR);
                }

            }
        } catch (Exception e) {
            log.error(e.getMessage());
            return ResponseMessage.error(CodeType.ERROR_OLD_PASSWORD);
        }

        return ResponseMessage.error(CodeType.ERROR_OLD_PASSWORD);
    }


    private ResponseMessage verifyDsspUserDetail(SysUserDetail userDetail) {
        ResponseMessage<?> msg = null;
        if (userDetail == null) {
            return ResponseMessage.error(CodeType.SMS_CODE_ERROR_USER_NOT_EXIST);
        }
//        if (Constants.USER_STATUS_DISABLED.equals(userDetail.getDisableFlag())) {
//            return ResponseMessage.error(UserState.Disabled.getCode(), UserState.Disabled.getDescription());
//        }
//        if (Constants.USER_LOGIN_STATUS_OK.equals(userDetail.getLoginStatus())) {
//            return ResponseMessage.error(UserState.LOGIN_JOBING.getCode(), UserState.LOGIN_JOBING.getDescription());
//        }

        String token = userDetail.getToken();
        token = safe_header + token;
        userDetail.setToken(token);
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletResponse response = attributes.getResponse();
        //没必要.
        this.setTokenToHeader(response, userDetail.getToken());
        msg = ResponseMessage.success(userDetail);

        return msg;
    }

    /**
    * @Description: 登录
    * @Author: ldg
    * @Date: 2020/10/15
    */
    @PostMapping("/login")
    public ResponseMessage login(@RequestBody LoginEntity loginEntity) {

        log.info("login params:{}", JSONObject.toJSONString(loginEntity));
        String userName = StringUtil.isNotEmpty(loginEntity.getLoginEmail()) ? loginEntity.getLoginEmail() : loginEntity.getPhone();

        ResponseMessage<?> msg = null;
        try {
            SysUserDetail userDetail = service.login(userName, loginEntity.getPassword());
            msg = verifyDsspUserDetail(userDetail);
//            //更新小程序用的id
//            if(!msg.isError()){
//                if (!StringUtils.isEmpty(loginEntity.getOpenId())) {
//                    service.updateUserOpenId(loginEntity);
//                }
//            }
            if(!msg.isError()){
                if (!StringUtils.isEmpty(loginEntity.getPhone()) || !StringUtils.isEmpty(loginEntity.getLoginEmail())) {
                    loginEntity.setLoginStatus(1);
                    service.updateLoginStatus(loginEntity);
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            return ResponseMessage.error(CodeType.ERROR_PASSWORD.getCode(), CodeType.ERROR_PASSWORD.getDescription());
        }
        return msg;
    }

    private void setTokenToHeader(HttpServletResponse response, String token) {
        response.setHeader(strTokenHeader, token);
    }

    /**
     * @RequestParam String username
     * @return
     */
//    @ApiOperation("登出")
    @PostMapping("/logout")
    public ResponseMessage logout(@RequestBody LoginEntity loginEntity) {

        if (StringUtils.isBlank(loginEntity.getPhone())) {
            return ResponseMessage.error(CodeType.LOGOUT_FAIL.getCode(), CodeType.LOGOUT_FAIL.getDescription());
        }
        loginEntity.setLoginStatus(0);
        service.updateLoginStatus(loginEntity);
        return ResponseMessage.success("logout");
    }

//    @Deprecated
//    @ApiOperation("注册")
//    @PostMapping("/register")
//    public ResponseMessage register(@RequestBody LoginEntity loginEntity) {
//        if (StringUtils.isAnyBlank(loginEntity.getPassword())) {
//            return ResponseMessage.error(CodeType.TOKEN_PARAMETER_ERROR.getCode(),
//                    CodeType.TOKEN_PARAMETER_ERROR.getDescription());
//        }
//        //验证手机号
//        if (StringUtil.isNotEmpty(loginEntity.getPhone()) && !CheckUtil.isPhone(loginEntity.getPhone())) {
//            return ResponseMessage.error(CodeType.PHONE_ERROR.getCode(), CodeType.PHONE_ERROR.getDescription());
//        }
//
////        Role role = new Role();
////        role.setRoleId(loginEntity.getRoleId());
//        DsspUserDetail userDetail = new DsspUserDetail(loginEntity.getLoginEmail(),
//                loginEntity.getPassword(),
//                loginEntity.getPhone(),
//                loginEntity.getCompanyId());
//        String username = null;
//        if(StringUtil.isEmpty(loginEntity.getUserName())){
//            if(StringUtil.isEmpty(loginEntity.getLoginEmail()) || StringUtil.isEmpty(loginEntity.getPhone())){
//                return ResponseMessage.error(CodeType.MISSING_PARAME);
//            }else{
//                if(StringUtil.isNotEmpty(loginEntity.getLoginEmail())){
//                    username = loginEntity.getLoginEmail();
//                }else{
//                    username = loginEntity.getPhone();
//                }
//            }
//        }else {
//            username = loginEntity.getUserName();
//        }
//        userDetail.setUsername(username);
//        userDetail.setEmail(StringUtils.isNoneBlank(loginEntity.getLoginEmail()) ? loginEntity.getLoginEmail() : "");
//        userDetail.setCompanyType(loginEntity.getCompanyType());
//        //冗余一下.
//        userDetail.setPlatId(loginEntity.getCompanyType());
//        try {
//            userDetail = service.register(userDetail);
//        } catch (Exception ex) {
//            return ResponseMessage.error(CodeType.REGISTER_DSP_ERROR, ex.getMessage());
//        }
//        ResponseMessage<Integer> msg = ResponseMessage.success(Integer.valueOf(userDetail.getId()));
//        return msg;
//    }


//    @ApiOperation("根据token返回用户信息.")
    @PostMapping("/findByToken")
    public ResponseMessage<SysUserDetail> findByToken() {
        //获取token
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String token = request.getHeader(HEADER_AUTHORIZATION);
        String userId = JwtUtil.getUserIdFromToken(token);

        if (StringUtil.isEmpty(userId)) {
            return null;
        } else {
            SysUserDetail userVO = new SysUserDetail();
            userVO.setId(Integer.parseInt(userId));
//            userVO = mapper.getUserVO(userVO);

            SysUserDetail userDetail = new SysUserDetail();
//            userDetail = userDetail.bulidDsspUserDetail(userDetail,userVO,mapper.getRoleList(userVO),mapper.getRuleList(userVO));

//            if (userDetail == null) {
//                ResponseMessage<BaseUser> err = new ResponseMessage<BaseUser>(CodeType.TOKEN_UNAUTHORIZED, null, false);
//                return err;
//            }
            ResponseMessage<SysUserDetail> result = ResponseMessage.success(userDetail);
            return result;
        }
    }

//    @Deprecated
//    @ApiOperation("根据platId返回企业用户信息.")
//    @PostMapping("/getUsersByPlatId")
//    public ResponseMessage<?> getUsersByPlatId(Integer platId, String companyName) {
//        List<DsspUserDetail> users;
//        if (platId.equals(PlatIds.dsp) || platId.equals(PlatIds.ssp)) {
//            users = mapper.findUsersByPlatId(platId, companyName);
//        } else {
//            return ResponseMessage.error(CodeType.MISSING_PARAME);
//        }
//
//        if (users != null) {
//            List<BaseUser> lst = new ArrayList<>();
//            users.forEach((ele) -> {
////                lst.add(ele.buildBaseUser());
//            });
//            ResponseMessage<List<BaseUser>> rsp = ResponseMessage.success(lst);
//            return rsp;
//        } else {
//            return ResponseMessage.error(CodeType.MISSING_PARAME);
//        }
//    }

//    @Deprecated
//    @ApiOperation("获取用户的openid")
//    @PostMapping("/getWeixinOpenId")
//    public ResponseMessage getWeixinOpenId(@RequestBody JSONObject jsonObject) {
//        String jsCode = jsonObject.getString("jsCode");
//        String url = String.format(weixinUrl, jsCode);
//        RestTemplate restTemplate = new RestTemplate();
//        String resp = restTemplate.getForObject(url, String.class);
//        String openId = getOpenId(resp);
//        if (StringUtils.isEmpty(openId)) {
//            return ResponseMessage.error(CodeType.WEIXIN_LOGIN_ERROR, resp);
//        }
//        JSONObject result = new JSONObject();
//        DsspUserDetail userDetail = service.getUserDetailForOpenId(openId);
//        boolean exist = userDetail != null;
//        result.put("exist", exist);
//        result.put("openId", openId);
//        if (!exist) {
//            return ResponseMessage.success(result);
//        } else {
//            return ResponseMessage.success(result);
//        }
//    }
//
//    private String getOpenId(String txResp) {
//        JSONObject json = JSONObject.parseObject(txResp);
//        if (json.containsKey("errcode")) {
//            return StringUtils.EMPTY;
//        }
//        return json.getString("openid");
//    }

//    @ApiOperation("测试")
//    @PostMapping("/hello")
//    public ResponseMessage<DsspUserDetail> hello() {
//        log.info("-------------------hello-------------------");
//        return ResponseMessage.success();
//    }

//    /**
//     * 扫码状态.
//     *
//     * @return
//     */
//    @Deprecated
//    @PostMapping("/QRLoginState")
//    public ResponseMessage loginState(@RequestBody JSONObject params) {
//        String key = params.getString("key");
//        ThreeParam threeParam = templateManager.getData(TemplateIds.mobile_login, key, ThreeParam.class);
//        if (threeParam == null) {
//            //二维码失效.
//            return ResponseMessage.success(0);
//        } else if (StringUtils.isEmpty(threeParam.getParam2())) {
//            //等待扫码.
//            return ResponseMessage.success(1);
//        } else {
//            //扫码成功.
//            return ResponseMessage.success(threeParam.getParam3());
//        }
//    }

//    /**
//     * 扫码.
//     *
//     * @param params
//     * @return
//     */
//    @Deprecated
//    @PostMapping("/scanQR")
//    public ResponseMessage scanQR(@RequestBody JSONObject params) {
//        String key = params.getString("key");
//        String token = params.getString("token");
//        ThreeParam param = templateManager.getData(TemplateIds.mobile_login, key, ThreeParam.class);
//        if (param == null) {
//            return ResponseMessage.error(CodeType.QR_FAILED);
//        } else {
//            //传递token设置.
//            String userId = JwtUtil.getUserIdFromToken(token);
//            param.setParam2(userId);
//            param.setParam3(token);
//            boolean b = templateManager.updateRedis(TemplateIds.mobile_login, param);
//            return ResponseMessage.success(b);
//        }
//    }

    /**
     * 通过token进行登录.
     *
     * @param params
     * @return
     */
    @PostMapping("/loginFromToken")
    public ResponseMessage loginFromToken(@RequestBody JSONObject params) {
        String token = params.getString("token");
        if (StringUtils.isEmpty(token)) {
            return ResponseMessage.success(CodeType.QR_LOGIN_ERROR);
        }
        String userId = JwtUtil.getUserIdFromToken(token);
        if (StringUtils.isEmpty(userId)) {
            return ResponseMessage.success(CodeType.QR_LOGIN_ERROR);
        }
        SysUserDetail userVO = new SysUserDetail();
        userVO.setId(Integer.parseInt(userId));
//        userVO = mapper.getUserVO(userVO);

        SysUserDetail userDetail = new SysUserDetail();
//        userDetail = userDetail.bulidDsspUserDetail(userDetail,userVO,mapper.getRoleList(userVO),mapper.getRuleList(userVO));
        userDetail.setToken(token);
        return ResponseMessage.success(userDetail);
    }

//    public static void main(String[] args) {
//        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
//        String s = encoder.encode("a12345");
//        log.info("s={}",s);
//    }

}
View Code

12.业务层

package cn.likui.study.service.impl;

import cn.likui.study.enums.CodeType;
import cn.likui.study.entity.LoginEntity;
import cn.likui.study.entity.ResponseMessage;
import cn.likui.study.entity.SysUserDetail;
import cn.likui.study.exception.SysSecurityException;
import cn.likui.study.mapper.SysUserMapper;
import cn.likui.study.service.AuthService;
import cn.likui.study.utils.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;

/**
 * authservice实现类.
 * 角色注册,登陆等核心service.
 * 2
 */
@Slf4j
@Service
public class AuthServiceImpl implements AuthService {

    private final AuthenticationManager authenticationManager;
    private final UserDetailsService userDetailsService;
    private final SysUserMapper sysUserMapper;
//    @Autowired
//    private TemplateManager templateManager;

    @Autowired
    public AuthServiceImpl(AuthenticationManager authenticationManager,
                           @Qualifier("SysUserDetailsService") UserDetailsService userDetailsService,
                           SysUserMapper sysUserMapper) {
        this.authenticationManager = authenticationManager;
        this.userDetailsService = userDetailsService;
        this.sysUserMapper = sysUserMapper;
    }

    /**
     * 登录方法,过滤器只开放这个接口.
     * 调用之后会进入SpringSecurity认证体系.
     *
     * @param username
     * @param password
     * @return
     */
    @Override
    public SysUserDetail login(String username, String password) {
        //权限对象,会调用(UserDetailsService.loadUserByUsername)
        final Authentication authentication = authenticate(username, password);
        //存储到上下文中.
        SecurityContextHolder.getContext().setAuthentication(authentication);
        //到这里就算登陆ok了.
        final SysUserDetail userDetail = (SysUserDetail) authentication.getPrincipal();
        //生成token,会调用方法.(id,登陆账号).
        final String token = JwtUtil.createJwtToken(userDetail.getId(), username);
        log.info("-----------------------------generateAccessToken:{}", token);
        //token进行存储.
        userDetail.setToken(token);

        return userDetail;
    }
templateManager.updateRedis(TemplateIds.mobile_login, twoParam, timeoutSecond);
//        }
//    }

    /**
     * 该方法会去调用userDetailsService.loadUserByUsername()
     * 去验证用户名和密码,如果正确,则存储该用户名密码到“security 的 context中”
     * 2
     *
     * @param username
     * @param password
     * @return
     */
    private Authentication authenticate(String username, String password) {
        try {
            UsernamePasswordAuthenticationToken tokenService = new UsernamePasswordAuthenticationToken(username, password);
            Authentication auth = authenticationManager.authenticate(tokenService);
            return auth;
        } catch (DisabledException | BadCredentialsException e) {
            throw new SysSecurityException(ResponseMessage.error(CodeType.TOKEN_UNAUTHORIZED.getCode(), e.getMessage()));
        }
    }


}
View Code

13.登陆身份认证 

package cn.likui.study.service.impl;

import cn.likui.study.entity.SysUser;
import cn.likui.study.entity.SysUserDetail;
import cn.likui.study.mapper.SysUserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * 登陆身份认证.
 * 通过用户名获取用户对象.
 * 根据用户名获取数据库该用户信息,spring security在登录时自动调用
 * WebSecurityConfigurerAdapter会拿这里的User里的password与用户输入的对比验证
 * 3
 * @author
 */
@Slf4j
@Component(value = "SysUserDetailsService")
public class SysUserDetailsServiceImpl implements UserDetailsService {

    @Resource
    private SysUserMapper sysUserMapper;

    /**
     * 核心验证用户方法.(security框架调用)
     * 3
     * @param userName
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public SysUserDetail loadUserByUsername(String userName) throws UsernameNotFoundException {

        SysUser sysUser = new SysUser();
        sysUser.setUserName(userName);
        //TODO 查询数据
        sysUser = sysUserMapper.selectByPrimaryKey(null);
        if(sysUser == null){
            log.warn("------------------------用户不存在.-------------------------");
            return null;
        }

        SysUserDetail userDetail = new SysUserDetail();
        //TODO sysUser beanUtils copy  userDetail

        //权限集合.(本系统直接通过mysql获取,放置到role中.
        //设置权限(目前没用,随便设一个).
        List<GrantedAuthority> lstAuths = new ArrayList<>();
        lstAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
        userDetail.setAuthorities(lstAuths);

//        List<RoleVO> roleVOs = authMapper.getRoleList(userVO);
//        List<RuleVO> ruleVOs = authMapper.getRuleList(userVO);
//        userDetail = userDetail.bulidDsspUserDetail(userDetail,userVO,roleVOs,ruleVOs);
        log.info("SysUserDetail:", userDetail);
        return userDetail;
    }
}
View Code
原文地址:https://www.cnblogs.com/beixiaoyi/p/13820142.html