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); // } }
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())); } } }
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; } }
希望写博是我人生坚持在做的事情之一。