提交 65e938f3 编写于 作者: M ManongJu

JWT

上级 8b32bf63
......@@ -5,13 +5,7 @@ import lombok.Data;
import java.util.Date;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Mr.Yangxiufeng
* Date: 2018-06-13
* Time: 10:39
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MenuVo {
......
......@@ -6,13 +6,7 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.HashMap;
import java.util.Map;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Mr.Yangxiufeng
* Date: 2018-05-16
* Time: 11:04
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Result<T> {
......@@ -24,7 +18,6 @@ public class Result<T> {
private String description;
private T data;
private HashMap<String,Object> exend;
public Integer getCode() {
return code;
......@@ -59,17 +52,9 @@ public class Result<T> {
this.description = description;
}
@JsonIgnore
public HashMap<String, Object> getExend() {
return exend;
}
public void setExend(HashMap<String, Object> exend) {
this.exend = exend;
}
public Result() {
exend = new HashMap<>();
}
public static Result failure(int code, String msg) {
......@@ -81,13 +66,11 @@ public class Result<T> {
public static Result ok(String msg) {
Result result = new Result();
result.put("msg", msg);
return result;
}
public static Result ok(Map<String, Object> map) {
Result result = new Result();
result.exend.putAll(map);
return result;
}
......@@ -95,8 +78,5 @@ public class Result<T> {
return new Result();
}
public Result put(String key, Object value) {
exend.put(key, value);
return this;
}
}
......@@ -6,13 +6,7 @@ import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Mr.Yangxiufeng
* Date: 2018-05-10
* Time: 21:03
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class RoleVo implements Serializable {
......
......@@ -6,13 +6,7 @@ import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Mr.Yangxiufeng
* Date: 2018-05-10
* Time: 21:00
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UserVo implements Serializable {
......
......@@ -17,11 +17,11 @@
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
......
......@@ -16,11 +16,6 @@
<description>Demo project for Spring Boot</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
......@@ -34,11 +29,11 @@
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
</dependencies>
......
......@@ -26,11 +26,11 @@
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
......@@ -42,14 +42,10 @@
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>${spring-security-oauth.version}</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
......@@ -59,18 +55,7 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
......@@ -80,6 +65,11 @@
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>9.1.1</version>
</dependency>
</dependencies>
<build>
......
package com.microservice.skeleton.auth.config;
import com.microservice.skeleton.auth.error.MssWebResponseExceptionTranslator;
import com.microservice.skeleton.auth.service.impl.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import javax.sql.DataSource;
/**
* Created by Mr.Yangxiufeng on 2017/12/28.
* Time:11:02
* ProjectName:Mirco-Service-Skeleton
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private DataSource dataSource;
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Bean
RedisTokenStore redisTokenStore(){
return new RedisTokenStore(redisConnectionFactory);
}
//token存储数据库
// @Bean
// public JdbcTokenStore jdbcTokenStore(){
// return new JdbcTokenStore(dataSource);
// }
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetails());
}
@Bean
public ClientDetailsService clientDetails() {
return new JdbcClientDetailsService(dataSource);
}
@Bean
public WebResponseExceptionTranslator<OAuth2Exception> webResponseExceptionTranslator(){
return new MssWebResponseExceptionTranslator();
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(redisTokenStore())
.userDetailsService(userDetailsService)
.authenticationManager(authenticationManager);
endpoints.tokenServices(defaultTokenServices());
endpoints.exceptionTranslator(webResponseExceptionTranslator());//认证异常翻译
}
/**
* <p>注意,自定义TokenServices的时候,需要设置@Primary,否则报错,</p>
* @return
*/
@Primary
@Bean
public DefaultTokenServices defaultTokenServices(){
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(redisTokenStore());
tokenServices.setSupportRefreshToken(true);
tokenServices.setClientDetailsService(clientDetails());
tokenServices.setAccessTokenValiditySeconds(60*60*12); // token有效期自定义设置,默认12小时
tokenServices.setRefreshTokenValiditySeconds(60 * 60 * 24 * 7);//默认30天,这里修改
return tokenServices;
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()");
security .checkTokenAccess("isAuthenticated()");
security.allowFormAuthenticationForClients();
}
}
package com.microservice.skeleton.auth.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
/**
* <p>参看:https://github.com/spring-guides/tut-spring-security-and-angular-js/blob/master/oauth2-vanilla/README.adoc</p>
* Created by Mr.Yangxiufeng on 2017/12/29.
* Time:10:46
* ProjectName:Mirco-Service-Skeleton
*/
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter{
@Override
public void configure(HttpSecurity http) throws Exception {
http.
csrf().disable()
.authorizeRequests().anyRequest().authenticated()
.and()
.httpBasic();
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
super.configure(resources);
}
}
package com.microservice.skeleton.auth.config;
import com.microservice.skeleton.auth.service.impl.UserDetailsServiceImpl;
import com.microservice.skeleton.auth.jwt.JWTAuthenticationEntryPoint;
import com.microservice.skeleton.auth.jwt.JWTAuthenticationFilter;
import com.microservice.skeleton.auth.jwt.JWTAuthorizationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpMethod;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
/**
* Created by Mr.Yangxiufeng on 2017/12/27.
* Time:16:42
* ProjectName:Mirco-Service-Skeleton
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("userDetailsServiceImpl")
private UserDetailsService userDetailsService;
@Autowired
private UserDetailsServiceImpl userDetailsService;
private StringRedisTemplate redisTemplate;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
......@@ -45,17 +45,17 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
http.csrf().disable()
.authorizeRequests()
.anyRequest().fullyAuthenticated()
.antMatchers("/oauth/token").permitAll()
.antMatchers(HttpMethod.POST, "/login").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(new JWTAuthenticationFilter(authenticationManager() , redisTemplate), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new JWTAuthorizationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable();
.exceptionHandling().authenticationEntryPoint(new JWTAuthenticationEntryPoint());
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/css/**", "/js/**", "/plugins/**", "/favicon.ico");
}
}
package com.microservice.skeleton.auth.controller;
import com.microservice.skeleton.common.util.StatusCode;
import com.microservice.skeleton.common.vo.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.provider.token.ConsumerTokenServices;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Mr.Yangxiufeng
* Date: 2018-12-07
* Time: 19:17
*/
@RestController
public class LogoutController {
@Autowired
private ConsumerTokenServices consumerTokenServices;
@DeleteMapping(value = "/exit")
public @ResponseBody
Result revokeToken(String access_token){
Result msg = new Result();
if (consumerTokenServices.revokeToken(access_token)){
msg.setCode(StatusCode.SUCCESS_CODE);
msg.setMsg("注销成功");
}else {
msg.setCode(StatusCode.FAILURE_CODE);
msg.setMsg("注销失败");
}
return msg;
return Result.ok();
}
}
......@@ -5,12 +5,6 @@ import org.springframework.web.bind.annotation.RestController;
import java.security.Principal;
/**
* <p>必须要有,做验证</p>
* Created by Mr.Yangxiufeng on 2017/12/29.
* Time:10:43
* ProjectName:Mirco-Service-Skeleton
*/
@RestController
public class UserController {
@RequestMapping("/user")
......
package com.microservice.skeleton.auth.entity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.Set;
/**
* @author Mr.Yangxiufeng
* @date 2020-10-28
* @time 17:42
*/
public class AuthUser implements UserDetails {
private Integer userId;
private String password;
private final String username;
private Set<SimpleGrantedAuthority> authorities;
private final boolean accountNonExpired;
private final boolean accountNonLocked;
private final boolean credentialsNonExpired;
private final boolean enabled;
public AuthUser(String password, String username, Set<SimpleGrantedAuthority> authorities) {
this(username, password, authorities, true, true, true, true);
}
public AuthUser(String password, String username, Set<SimpleGrantedAuthority> authorities, boolean accountNonExpired, boolean accountNonLocked, boolean credentialsNonExpired, boolean enabled) {
this.password = password;
this.username = username;
this.authorities = authorities;
this.accountNonExpired = accountNonExpired;
this.accountNonLocked = accountNonLocked;
this.credentialsNonExpired = credentialsNonExpired;
this.enabled = enabled;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return accountNonExpired;
}
@Override
public boolean isAccountNonLocked() {
return accountNonLocked;
}
@Override
public boolean isCredentialsNonExpired() {
return credentialsNonExpired;
}
@Override
public boolean isEnabled() {
return enabled;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
}
package com.microservice.skeleton.auth.error;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.DefaultThrowableAnalyzer;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InsufficientScopeException;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.web.util.ThrowableAnalyzer;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import java.io.IOException;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Mr.Yangxiufeng
* Date: 2018-12-06
* Time: 16:28
*/
public class MssWebResponseExceptionTranslator implements WebResponseExceptionTranslator<OAuth2Exception> {
private ThrowableAnalyzer throwableAnalyzer = new DefaultThrowableAnalyzer();
@Override
public ResponseEntity<OAuth2Exception> translate(Exception e) throws Exception {
// Try to extract a SpringSecurityException from the stacktrace
Throwable[] causeChain = throwableAnalyzer.determineCauseChain(e);
Exception ase = (OAuth2Exception) throwableAnalyzer.getFirstThrowableOfType(OAuth2Exception.class, causeChain);
if (ase != null) {
return handleOAuth2Exception((OAuth2Exception) ase);
}
ase = (AuthenticationException) throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class,
causeChain);
if (ase != null) {
return handleOAuth2Exception(new MssWebResponseExceptionTranslator.UnauthorizedException(e.getMessage(), e));
}
ase = (AccessDeniedException) throwableAnalyzer
.getFirstThrowableOfType(AccessDeniedException.class, causeChain);
if (ase instanceof AccessDeniedException) {
return handleOAuth2Exception(new MssWebResponseExceptionTranslator.ForbiddenException(ase.getMessage(), ase));
}
ase = (HttpRequestMethodNotSupportedException) throwableAnalyzer.getFirstThrowableOfType(
HttpRequestMethodNotSupportedException.class, causeChain);
if (ase instanceof HttpRequestMethodNotSupportedException) {
return handleOAuth2Exception(new MssWebResponseExceptionTranslator.MethodNotAllowed(ase.getMessage(), ase));
}
return handleOAuth2Exception(new MssWebResponseExceptionTranslator.ServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase(), e));
}
private ResponseEntity<OAuth2Exception> handleOAuth2Exception(OAuth2Exception e) throws IOException {
int status = e.getHttpErrorCode();
String error = e.getOAuth2ErrorCode();
String summary = e.getSummary();
HttpHeaders headers = new HttpHeaders();
headers.set("Cache-Control", "no-store");
headers.set("Pragma", "no-cache");
if (status == HttpStatus.UNAUTHORIZED.value() || (e instanceof InsufficientScopeException)) {
headers.set("WWW-Authenticate", String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, e.getSummary()));
}
ResponseEntity<OAuth2Exception> response = new ResponseEntity<OAuth2Exception>(e, headers,
HttpStatus.valueOf(status));
return response;
}
public void setThrowableAnalyzer(ThrowableAnalyzer throwableAnalyzer) {
this.throwableAnalyzer = throwableAnalyzer;
}
@SuppressWarnings("serial")
private static class ForbiddenException extends OAuth2Exception {
public ForbiddenException(String msg, Throwable t) {
super(msg, t);
}
@Override
public String getOAuth2ErrorCode() {
return "access_denied";
}
@Override
public int getHttpErrorCode() {
return 403;
}
}
@SuppressWarnings("serial")
private static class ServerErrorException extends OAuth2Exception {
public ServerErrorException(String msg, Throwable t) {
super(msg, t);
}
@Override
public String getOAuth2ErrorCode() {
return "server_error";
}
@Override
public int getHttpErrorCode() {
return 500;
}
}
@SuppressWarnings("serial")
private static class UnauthorizedException extends OAuth2Exception {
public UnauthorizedException(String msg, Throwable t) {
super(msg, t);
}
@Override
public String getOAuth2ErrorCode() {
return "unauthorized";
}
@Override
public int getHttpErrorCode() {
return 401;
}
}
@SuppressWarnings("serial")
private static class MethodNotAllowed extends OAuth2Exception {
public MethodNotAllowed(String msg, Throwable t) {
super(msg, t);
}
@Override
public String getOAuth2ErrorCode() {
return "method_not_allowed";
}
@Override
public int getHttpErrorCode() {
return 405;
}
}
}
package com.microservice.skeleton.auth.jwt;
import com.alibaba.fastjson.JSONObject;
import com.microservice.skeleton.common.vo.Result;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author Mr.Yangxiufeng
* @date 2020-10-28
* @time 15:46
*/
public class JWTAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
String reason = authException.getMessage();
response.getWriter().write(JSONObject.toJSONString(Result.failure(HttpServletResponse.SC_FORBIDDEN, reason)));
}
}
package com.microservice.skeleton.auth.jwt;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.nacos.common.utils.Md5Utils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.microservice.skeleton.auth.entity.AuthUser;
import com.microservice.skeleton.common.vo.Result;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.Md5Crypt;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import sun.security.provider.MD5;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
* <p>认证</p>
* @author Mr.Yangxiufeng
* @date 2020-10-27
* @time 19:21
*/
@Slf4j
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private static final byte[] SECRET = "6MNSobBRCHGIO0fS6MNSobBRCHGIO0fS".getBytes();
/**
* 过期时间2小时
*/
private static final long EXPIRE_TIME = 1000 * 60 * 60 * 2;
private AuthenticationManager authenticationManager;
private StringRedisTemplate redisTemplate;
public JWTAuthenticationFilter(AuthenticationManager authenticationManager, StringRedisTemplate redisTemplate) {
this.authenticationManager = authenticationManager;
this.redisTemplate = redisTemplate;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
String username = request.getParameter("username");
String password = request.getParameter("password");
return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
}
@SneakyThrows
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
AuthUser user = (AuthUser) authResult.getPrincipal();
Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
/**
* 1、创建密钥
*/
MACSigner macSigner = new MACSigner(SECRET);
/**
* 2、payload
*/
String payload = JSONObject.toJSONString(user);
JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
.subject("subject")
.claim("payload", payload)
.expirationTime(new Date(System.currentTimeMillis() + EXPIRE_TIME))
.build();
JWSHeader jwsHeader = new JWSHeader(JWSAlgorithm.HS256);
/**
* 创建签名的JWT
*/
SignedJWT signedJWT = new SignedJWT(jwsHeader , claimsSet);
signedJWT.sign(macSigner);
/**
* 生成token
*/
String jwtToken = signedJWT.serialize();
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding("UTF-8");
Result result = Result.ok().setData(jwtToken);
//
String keyPrefix = "JWT" + user.getUserId() + ":";
String keySuffix = Md5Utils.getMD5(jwtToken.getBytes());
String key = keyPrefix + keySuffix;
redisTemplate.opsForValue().set(key , jwtToken , EXPIRE_TIME , TimeUnit.SECONDS);
response.getWriter().write(JSONObject.toJSONString(result));
}
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
log.error("登录认证失败",failed);
Result result = null;
int status = 401;
if (failed instanceof UsernameNotFoundException){
result = Result.failure(404, "用户不存在");
}else if (failed instanceof BadCredentialsException){
result = Result.failure(401, "用户名密码错误");
}
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding("UTF-8");
response.setStatus(status);
response.getWriter().write(JSONObject.toJSONString(result));
}
}
package com.microservice.skeleton.auth.jwt;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.common.utils.Md5Utils;
import com.microservice.skeleton.auth.entity.AuthUser;
import com.microservice.skeleton.common.vo.Result;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jose.crypto.MACVerifier;
import com.nimbusds.jwt.SignedJWT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.StringUtils;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.ParseException;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**<p>授权</p>
* @author Mr.Yangxiufeng
* @date 2020-10-27
* @time 19:23
*/
@Slf4j
public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
private static final byte[] SECRET = "6MNSobBRCHGIO0fS6MNSobBRCHGIO0fS".getBytes();
public static final String TOKEN_HEADER = "Authorization";
public static final String TOKEN_PREFIX = "Bearer ";
public JWTAuthorizationFilter(AuthenticationManager authenticationManager) {
super(authenticationManager);
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String token = request.getHeader(TOKEN_HEADER);
if (StringUtils.isEmpty(token) || !token.startsWith(TOKEN_PREFIX)){
chain.doFilter(request,response);
return;
}
try {
Authentication authentication = getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
onSuccessfulAuthentication(request , response , authentication);
chain.doFilter(request,response);
} catch (Exception e) {
e.printStackTrace();
onUnsuccessfulAuthentication(request, response , new AccountExpiredException(e.getMessage()));
}
}
@Override
protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) throws IOException {
log.info("Token 验证成功");
}
@Override
protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException {
log.error("token校验失败");
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding("UTF-8");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
Result result = Result.failure(HttpServletResponse.SC_UNAUTHORIZED , failed.getMessage());
response.getWriter().write(JSONObject.toJSONString(result));
}
// 这里从token中获取用户信息并新建一个token
private UsernamePasswordAuthenticationToken getAuthentication(String tokenHeader) throws ParseException, JOSEException {
String token = tokenHeader.replace(TOKEN_PREFIX, "");
SignedJWT jwt = SignedJWT.parse(token);
JWSVerifier verifier = new MACVerifier(SECRET);
//校验是否有效
if (!jwt.verify(verifier)) {
throw new AccountExpiredException("Token 无效");
}
//校验超时
Date expirationTime = jwt.getJWTClaimsSet().getExpirationTime();
if (new Date().after(expirationTime)) {
throw new AccountExpiredException("Token 已过期");
}
//获取载体中的数据
Object account = jwt.getJWTClaimsSet().getClaim("payload");
if (account != null){
AuthUser user = JSONObject.parseObject(account.toString(), AuthUser.class);
return new UsernamePasswordAuthenticationToken(user.getUsername(), null, user.getAuthorities());
}
return null;
}
}
package com.microservice.skeleton.auth.service;
import com.microservice.skeleton.auth.service.impl.RoleServiceImpl;
import com.microservice.skeleton.common.vo.Result;
import com.microservice.skeleton.common.vo.RoleVo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.List;
/**
* Created by Mr.Yangxiufeng on 2017/12/29.
* Time:12:30
* ProjectName:Mirco-Service-Skeleton
*/
@FeignClient(name = "mss-upms",fallback = RoleServiceImpl.class)
public interface RoleService {
@GetMapping("role/getRoleByUserId/{userId}")
Result<List<RoleVo>> getRoleByUserId(@PathVariable("userId") Integer userId);
}
package com.microservice.skeleton.auth.service;
import com.microservice.skeleton.auth.service.impl.PermissionServiceImpl;
import com.microservice.skeleton.auth.service.impl.UpmsServiceFallbackFactory;
import com.microservice.skeleton.common.vo.MenuVo;
import com.microservice.skeleton.common.vo.Result;
import com.microservice.skeleton.common.vo.RoleVo;
import com.microservice.skeleton.common.vo.UserVo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
......@@ -11,12 +12,18 @@ import org.springframework.web.bind.annotation.PathVariable;
import java.util.List;
/**
* Created by Mr.Yangxiufeng on 2017/12/29.
* Time:12:37
* ProjectName:Mirco-Service-Skeleton
* @author Mr.Yangxiufeng
* @date 2020-10-28
* @time 16:49
*/
@FeignClient(name = "mss-upms",fallback = PermissionServiceImpl.class)
public interface PermissionService {
@FeignClient(name = "mss-upms",fallbackFactory = UpmsServiceFallbackFactory.class)
public interface UpmsService {
@GetMapping("user/findByUsername/{username}")
Result<UserVo> findByUsername(@PathVariable("username") String username);
@GetMapping("role/getRoleByUserId/{userId}")
Result<List<RoleVo>> getRoleByUserId(@PathVariable("userId") Integer userId);
@GetMapping("permission/getRolePermission/{roleId}")
Result<List<MenuVo>> getRolePermission(@PathVariable("roleId") Integer roleId);
}
package com.microservice.skeleton.auth.service;
import com.microservice.skeleton.auth.service.impl.UserServiceImpl;
import com.microservice.skeleton.common.vo.Result;
import com.microservice.skeleton.common.vo.UserVo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* Created by Mr.Yangxiufeng on 2017/12/27.
* Time:15:12
* ProjectName:Mirco-Service-Skeleton
*/
@FeignClient(name = "mss-upms",fallback = UserServiceImpl.class)
public interface UserService {
@GetMapping("user/findByUsername/{username}")
Result<UserVo> findByUsername(@PathVariable("username") String username);
}
package com.microservice.skeleton.auth.service.impl;
import com.microservice.skeleton.auth.service.PermissionService;
import com.microservice.skeleton.common.vo.MenuVo;
import com.microservice.skeleton.common.vo.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Mr.Yangxiufeng
* Date: 2018-06-13
* Time: 11:14
*/
@Slf4j
@Service
public class PermissionServiceImpl implements PermissionService {
@Override
public Result<List<MenuVo>> getRolePermission(Integer roleId) {
log.info("调用{}失败","getRolePermission");
return Result.failure(100,"调用getRolePermission失败");
}
}
package com.microservice.skeleton.auth.service.impl;
import com.microservice.skeleton.auth.service.RoleService;
import com.microservice.skeleton.common.vo.Result;
import com.microservice.skeleton.common.vo.RoleVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Mr.Yangxiufeng
* Date: 2018-06-13
* Time: 11:06
*/
@Service
@Slf4j
public class RoleServiceImpl implements RoleService {
@Override
public Result<List<RoleVo>> getRoleByUserId(Integer userId) {
log.info("调用{}失败","getRoleByUserId");
return Result.failure(100,"调用getRoleByUserId失败");
}
}
package com.microservice.skeleton.auth.service.impl;
import com.microservice.skeleton.auth.service.UpmsService;
import com.microservice.skeleton.common.vo.MenuVo;
import com.microservice.skeleton.common.vo.Result;
import com.microservice.skeleton.common.vo.RoleVo;
import com.microservice.skeleton.common.vo.UserVo;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author Mr.Yangxiufeng
* @date 2020-10-28
* @time 16:53
*/
@Slf4j
@Component
public class UpmsServiceFallbackFactory implements FallbackFactory<UpmsService> {
@Override
public UpmsService create(Throwable throwable) {
log.error("调用UPMS失败", throwable);
return new UpmsService() {
@Override
public Result<UserVo> findByUsername(String username) {
return Result.failure(201,"调用失败");
}
@Override
public Result<List<RoleVo>> getRoleByUserId(Integer userId) {
return Result.failure(201,"调用失败");
}
@Override
public Result<List<MenuVo>> getRolePermission(Integer roleId) {
return Result.failure(201,"调用失败");
}
};
}
}
package com.microservice.skeleton.auth.service.impl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.microservice.skeleton.auth.service.PermissionService;
import com.microservice.skeleton.auth.service.RoleService;
import com.microservice.skeleton.auth.service.UserService;
import com.microservice.skeleton.auth.entity.AuthUser;
import com.microservice.skeleton.auth.service.UpmsService;
import com.microservice.skeleton.common.util.StatusCode;
import com.microservice.skeleton.common.vo.MenuVo;
import com.microservice.skeleton.common.vo.Result;
......@@ -17,61 +15,50 @@ import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Created by Mr.Yangxiufeng on 2017/12/27.
* Time:16:37
* ProjectName:Mirco-Service-Skeleton
*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserService userService;
@Autowired
private RoleService roleService;
@Autowired
private PermissionService permissionService;
private ObjectMapper objectMapper = new ObjectMapper();
private UpmsService upmsService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Result<UserVo> userResult = userService.findByUsername(username);
Result<UserVo> userResult = upmsService.findByUsername(username);
if (userResult.getCode() != StatusCode.SUCCESS_CODE) {
throw new UsernameNotFoundException("用户:" + username + ",不存在!");
}
Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
boolean enabled = true; // 可用性 :true:可用 false:不可用
boolean accountNonExpired = true; // 过期性 :true:没过期 false:过期
boolean credentialsNonExpired = true; // 有效性 :true:凭证有效 false:凭证无效
boolean accountNonLocked = true; // 锁定性 :true:未锁定 false:已锁定
Set<SimpleGrantedAuthority> grantedAuthorities = new HashSet<>();
UserVo userVo = new UserVo();
BeanUtils.copyProperties(userResult.getData(),userVo);
Result<List<RoleVo>> roleResult = roleService.getRoleByUserId(userVo.getId());
if (roleResult.getCode() != StatusCode.SUCCESS_CODE){
Result<List<RoleVo>> roleResult = upmsService.getRoleByUserId(userVo.getId());
if (roleResult.getCode() == StatusCode.SUCCESS_CODE){
List<RoleVo> roleVoList = roleResult.getData();
for (RoleVo role:roleVoList){
//角色必须是ROLE_开头,可以在数据库中设置
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_"+role.getValue());
SimpleGrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_"+role.getValue());
grantedAuthorities.add(grantedAuthority);
//获取权限
Result<List<MenuVo>> perResult = permissionService.getRolePermission(role.getId());
if (perResult.getCode() != StatusCode.SUCCESS_CODE){
Result<List<MenuVo>> perResult = upmsService.getRolePermission(role.getId());
if (perResult.getCode() == StatusCode.SUCCESS_CODE){
List<MenuVo> permissionList = perResult.getData();
for (MenuVo menu:permissionList
) {
GrantedAuthority authority = new SimpleGrantedAuthority(menu.getCode());
grantedAuthorities.add(authority);
if ( !StringUtils.isEmpty(menu.getUrl()) ){
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(menu.getUrl());
grantedAuthorities.add(authority);
}
}
}
}
}
User user = new User(userVo.getUsername(), userVo.getPassword(),
enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, grantedAuthorities);
AuthUser user = new AuthUser(userVo.getUsername(), userVo.getPassword(), grantedAuthorities);
user.setUserId(userVo.getId());
return user;
}
}
package com.microservice.skeleton.auth.service.impl;
import com.microservice.skeleton.auth.service.UserService;
import com.microservice.skeleton.common.vo.Result;
import com.microservice.skeleton.common.vo.UserVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Mr.Yangxiufeng
* Date: 2018-06-13
* Time: 10:56
*/
@Service
@Slf4j
public class UserServiceImpl implements UserService {
@Override
public Result<UserVo> findByUsername(String username) {
log.info("调用{}失败","findByUsername");
return Result.failure(100,"调用findByUsername接口失败");
}
}
server:
port: 9060
spring:
jpa:
show-sql: true
datasource:
url: jdbc:mysql://localhost:3306/zuul-auth?useUnicode=true&characterEncoding=utf-8
username: root
password: 123456
druid:
driver-class-name: com.mysql.jdbc.Driver
redis:
host: 127.0.0.1
port: 6379
......@@ -17,13 +9,10 @@ spring:
nacos:
discovery:
server-addr: 127.0.0.1:8848
logging:
config: classpath:logback.xml
level:
org:
springframework:
web: info
root: INFO
org.springframework.web: INFO
###feign 默认关闭熔断,请看HystrixFeignConfiguration
feign:
hystrix:
......
package com.microservice.skeleton.auth;
import com.microservice.skeleton.auth.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class AuthCenterApplicationTests {
@Autowired
UserService userService;
@Test
public void contextLoads() {
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
System.out.println(passwordEncoder.encode("123456"));
System.out.println(passwordEncoder.matches("123456","$2a$10$Auj1gIQ7y2CqZkz1P0/GNOV4CNVjZ8qjeUVgztU7GjL6sF/08ebVO"));
}
}
......@@ -25,11 +25,11 @@
<dependencies>
<!--注册中心-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
......
......@@ -2,15 +2,20 @@ server:
port: 9021
spring:
datasource:
url: jdbc:mysql://localhost:3306/zuul-auth?useUnicode=true&characterEncoding=utf-8
url: jdbc:mysql://localhost:3306/zuul-auth?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
druid:
driver-class-name: com.mysql.jdbc.Driver
max-active: 200
max-wait: 30000
initial-size: 5
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
mybatis:
mapper-locations: classpath:mapper/*.xml
\ No newline at end of file
......@@ -15,11 +15,10 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR2</spring-cloud.version>
<spring-cloud-alibaba.version>0.2.1.RELEASE</spring-cloud-alibaba.version>
<druid-starter.version>1.1.10</druid-starter.version>
<spring-cloud.version>Hoxton.SR8</spring-cloud.version>
<spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
<druid-starter.version>1.1.16</druid-starter.version>
<swagger2.version>2.9.2</swagger2.version>
<lombok.version>1.16.20</lombok.version>
<mybatis-plus.version>2.2.0</mybatis-plus.version>
<tk.mybatis.starter.version>2.0.4</tk.mybatis.starter.version>
<!--升级SpringBoot2.0.x后出现Which fixed NoSuchMethodError.RedisConnection.set([B[B)V issue
......@@ -31,7 +30,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.8.RELEASE</version>
<version>2.2.10.RELEASE</version>
</parent>
<modules>
<module>mss-common</module>
......@@ -63,17 +62,12 @@
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册