Browse Source

jwt 密钥校验

yufeng0528 4 years ago
parent
commit
bb1fc28f29

+ 0 - 25
spring5-admin/src/main/java/com/yaozhitech/spring5/config/RoleResourceConfiguration.java

@@ -1,25 +0,0 @@
1
-package com.yaozhitech.spring5.config;
2
-
3
-import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
4
-import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
5
-import org.springframework.context.annotation.Configuration;
6
-
7
-@Configuration
8
-public class RoleResourceConfiguration extends ShiroConfiguration {
9
-	
10
-	@Override
11
-	public ShiroFilterChainDefinition shiroFilterChainDefinition() {
12
-		
13
-		
14
-		DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
15
-//    chainDefinition.addPathDefinition("/login", "noSessionCreation,anon");  //login不做认证,noSessionCreation的作用是用户在操作session时会抛异常
16
-//    chainDefinition.addPathDefinition("/logout", "noSessionCreation,authcToken[permissive]"); //做用户认证,permissive参数的作用是当token无效时也允许请求访问,不会返回鉴权未通过的错误
17
-        chainDefinition.addPathDefinition("/**", "anon");
18
-//		chainDefinition.addPathDefinition("/**", "noSessionCreation,authcToken"); // 只允许admin或manager角色的用户访问
19
-//		chainDefinition.addPathDefinition("/article/list", "noSessionCreation,authc");
20
-//		chainDefinition.addPathDefinition("/article/*", "noSessionCreation,authc[permissive]");
21
-//		chainDefinition.addPathDefinition("/**", "noSessionCreation,authc"); // 默认进行用户鉴权
22
-		
23
-		return chainDefinition;
24
-	}
25
-}

+ 10 - 10
spring5-auth/spring5-auth-client/pom.xml

@@ -15,18 +15,18 @@
15 15
     </parent>
16 16
     
17 17
 	<dependencies>
18
-	    <!-- Spring Boot 响应式 Redis 依赖 -->
19
-        <dependency>
20
-            <groupId>org.springframework.boot</groupId>
21
-            <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
22
-        </dependency>
18
+<!-- 	    Spring Boot 响应式 Redis 依赖 -->
19
+<!--         <dependency> -->
20
+<!--             <groupId>org.springframework.boot</groupId> -->
21
+<!--             <artifactId>spring-boot-starter-data-redis-reactive</artifactId> -->
22
+<!--         </dependency> -->
23 23
         
24 24
 	    <!-- shrio -->
25
-        <dependency>
26
-            <groupId>org.apache.shiro</groupId>
27
-            <artifactId>shiro-spring-boot-web-starter</artifactId>
28
-            <version>1.4.0</version>
29
-        </dependency>
25
+<!--         <dependency> -->
26
+<!--             <groupId>org.apache.shiro</groupId> -->
27
+<!--             <artifactId>shiro-spring-boot-web-starter</artifactId> -->
28
+<!--             <version>1.4.0</version> -->
29
+<!--         </dependency> -->
30 30
         
31 31
         <!-- jwt -->
32 32
         <dependency>

+ 0 - 99
spring5-auth/spring5-auth-client/src/main/java/com/yaozhitech/spring5/config/ShiroConfiguration.java

@@ -1,99 +0,0 @@
1
-package com.yaozhitech.spring5.config;
2
-
3
-import java.util.Arrays;
4
-import java.util.Map;
5
-
6
-import javax.servlet.DispatcherType;
7
-import javax.servlet.Filter;
8
-
9
-import org.apache.shiro.authc.Authenticator;
10
-import org.apache.shiro.authc.pam.FirstSuccessfulStrategy;
11
-import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
12
-import org.apache.shiro.mgt.SecurityManager;
13
-import org.apache.shiro.mgt.SessionStorageEvaluator;
14
-import org.apache.shiro.realm.Realm;
15
-import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
16
-import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
17
-import org.apache.shiro.web.mgt.DefaultWebSessionStorageEvaluator;
18
-import org.springframework.boot.web.servlet.FilterRegistrationBean;
19
-import org.springframework.context.annotation.Bean;
20
-import org.springframework.context.annotation.Configuration;
21
-
22
-import com.yaozhitech.spring5.filter.AnyRolesAuthorizationFilter;
23
-import com.yaozhitech.spring5.filter.JwtAuthFilter;
24
-import com.yaozhitech.spring5.jwt.JWTShiroRealm;
25
-import com.yaozhitech.spring5.service.JwtUserService;
26
-
27
-@Configuration
28
-public abstract class ShiroConfiguration {
29
-	/**
30
-	 * 注册shiro的Filter,拦截请求
31
-	 */
32
-	@Bean
33
-    public FilterRegistrationBean<Filter> filterRegistrationBean(SecurityManager securityManager,JwtUserService userService) throws Exception{
34
-        FilterRegistrationBean<Filter> filterRegistration = new FilterRegistrationBean<Filter>();
35
-        filterRegistration.setFilter((Filter)shiroFilter(securityManager, userService).getObject());
36
-        filterRegistration.addInitParameter("targetFilterLifecycle", "true");
37
-        filterRegistration.setAsyncSupported(true);
38
-        filterRegistration.setEnabled(true);
39
-        filterRegistration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC);
40
-
41
-        return filterRegistration;
42
-    }
43
-
44
-    @Bean
45
-    public Authenticator authenticator(JwtUserService userService) {
46
-        ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();
47
-        authenticator.setRealms(Arrays.asList(jwtShiroRealm(userService)));
48
-        authenticator.setAuthenticationStrategy(new FirstSuccessfulStrategy());
49
-        return authenticator;
50
-    }
51
-
52
-	/**
53
-	 * 禁用session, 不保存用户登录状态。保证每次请求都重新认证。
54
-	 * 需要注意的是,如果用户代码里调用Subject.getSession()还是可以用session,如果要完全禁用,要配合下面的noSessionCreation的Filter来实现
55
-	 */
56
-    @Bean
57
-    protected SessionStorageEvaluator sessionStorageEvaluator(){
58
-        DefaultWebSessionStorageEvaluator sessionStorageEvaluator = new DefaultWebSessionStorageEvaluator();
59
-        sessionStorageEvaluator.setSessionStorageEnabled(false);
60
-        return sessionStorageEvaluator;
61
-    }
62
-    
63
-    /**
64
-          * 用于JWT token认证的realm
65
-     */
66
-    @Bean("jwtRealm")
67
-    public Realm jwtShiroRealm(JwtUserService userService) {
68
-        JWTShiroRealm myShiroRealm = new JWTShiroRealm(userService);
69
-        return myShiroRealm;
70
-    }
71
-
72
-    /**
73
-          * 设置过滤器,将自定义的Filter加入
74
-     */
75
-    @Bean
76
-    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager, JwtUserService userService) {
77
-    	ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
78
-        factoryBean.setSecurityManager(securityManager);
79
-        Map<String, Filter> filterMap = factoryBean.getFilters();
80
-        filterMap.put("authcToken", createAuthFilter(userService));
81
-        filterMap.put("anyRole", createRolesFilter());
82
-        factoryBean.setFilters(filterMap);
83
-        factoryBean.setFilterChainDefinitionMap(shiroFilterChainDefinition().getFilterChainMap());
84
-
85
-        return factoryBean;
86
-    }
87
-    
88
-    public abstract ShiroFilterChainDefinition shiroFilterChainDefinition() ;
89
-
90
-   //注意不要加@Bean注解,不然spring会自动注册成filter
91
-    protected JwtAuthFilter createAuthFilter(JwtUserService userService){
92
-        return new JwtAuthFilter(userService);
93
-    }
94
-
95
-    protected AnyRolesAuthorizationFilter createRolesFilter(){
96
-        return new AnyRolesAuthorizationFilter();
97
-    }
98
-    
99
-}

+ 0 - 16
spring5-auth/spring5-auth-client/src/main/java/com/yaozhitech/spring5/dto/UserDto.java

@@ -1,16 +0,0 @@
1
-package com.yaozhitech.spring5.dto;
2
-
3
-import java.util.List;
4
-
5
-import lombok.Data;
6
-
7
-@Data
8
-public class UserDto {
9
-
10
-	private String username;
11
-    private char[] password;
12
-    private String encryptPwd;
13
-    private Long userId;
14
-    private String salt;
15
-    private List<String> roles;
16
-}

+ 0 - 43
spring5-auth/spring5-auth-client/src/main/java/com/yaozhitech/spring5/filter/AnyRolesAuthorizationFilter.java

@@ -1,43 +0,0 @@
1
-package com.yaozhitech.spring5.filter;
2
-
3
-import java.io.IOException;
4
-
5
-import javax.servlet.ServletRequest;
6
-import javax.servlet.ServletResponse;
7
-import javax.servlet.http.HttpServletResponse;
8
-
9
-import org.apache.shiro.subject.Subject;
10
-import org.apache.shiro.web.filter.authz.AuthorizationFilter;
11
-import org.apache.shiro.web.util.WebUtils;
12
-import org.springframework.http.HttpStatus;
13
-
14
-public class AnyRolesAuthorizationFilter  extends AuthorizationFilter {
15
-	
16
-	@Override
17
-    protected void postHandle(ServletRequest request, ServletResponse response){
18
-	}
19
-
20
-    @Override
21
-    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object mappedValue) throws Exception {
22
-        Subject subject = getSubject(servletRequest, servletResponse);
23
-        String[] rolesArray = (String[]) mappedValue;
24
-        if (rolesArray == null || rolesArray.length == 0) { //没有角色限制,有权限访问
25
-            return true;
26
-        }
27
-        for (String role : rolesArray) {
28
-            if (subject.hasRole(role)) //若当前用户是rolesArray中的任何一个,则有权限访问
29
-                return true;
30
-        }
31
-        return false;
32
-    }
33
-
34
-    @Override
35
-    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
36
-        HttpServletResponse httpResponse = WebUtils.toHttp(response);
37
-        httpResponse.setCharacterEncoding("UTF-8");
38
-        httpResponse.setContentType("application/json;charset=utf-8");
39
-        httpResponse.setStatus(HttpStatus.UNAUTHORIZED.ordinal());
40
-        return false;
41
-    }
42
-
43
-}

+ 0 - 152
spring5-auth/spring5-auth-client/src/main/java/com/yaozhitech/spring5/filter/JwtAuthFilter.java

@@ -1,152 +0,0 @@
1
-package com.yaozhitech.spring5.filter;
2
-
3
-
4
-import java.time.LocalDateTime;
5
-import java.time.ZoneId;
6
-import java.util.Date;
7
-
8
-import javax.servlet.ServletRequest;
9
-import javax.servlet.ServletResponse;
10
-import javax.servlet.http.HttpServletRequest;
11
-import javax.servlet.http.HttpServletResponse;
12
-
13
-import org.apache.shiro.authc.AuthenticationException;
14
-import org.apache.shiro.authc.AuthenticationToken;
15
-import org.apache.shiro.subject.Subject;
16
-import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
17
-import org.apache.shiro.web.util.WebUtils;
18
-import org.springframework.beans.factory.annotation.Value;
19
-import org.springframework.util.StringUtils;
20
-import org.springframework.web.bind.annotation.RequestMethod;
21
-
22
-import com.yaozhitech.spring5.dto.UserDto;
23
-import com.yaozhitech.spring5.jwt.JWTToken;
24
-import com.yaozhitech.spring5.service.JwtUserService;
25
-import com.yaozhitech.spring5.utils.JwtUtils;
26
-
27
-import lombok.extern.slf4j.Slf4j;
28
-
29
-@Slf4j
30
-public class JwtAuthFilter extends AuthenticatingFilter {
31
-	
32
-	@Value("${jwt.header}")
33
-    private String tokenHeader;
34
-
35
-    @Value("${jwt.tokenHead}")
36
-    private String tokenHead;
37
-
38
-    private static final int tokenRefreshInterval = 300;
39
-    private JwtUserService userService;
40
-
41
-    public JwtAuthFilter(JwtUserService userService){
42
-        this.userService = userService;
43
-        this.setLoginUrl("/login");
44
-    }
45
-
46
-    @Override
47
-    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
48
-        HttpServletRequest httpServletRequest = WebUtils.toHttp(request);
49
-        if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) //对于OPTION请求做拦截,不做token校验
50
-            return false;
51
-
52
-        return super.preHandle(request, response);
53
-    }
54
-
55
-    @Override
56
-    protected void postHandle(ServletRequest request, ServletResponse response){
57
-        this.fillCorsHeader(WebUtils.toHttp(request), WebUtils.toHttp(response));
58
-    }
59
-
60
-    /**
61
-          * 父类会在请求进入拦截器后调用该方法,返回true则继续,返回false则会调用onAccessDenied()。这里在不通过时,还调用了isPermissive()方法,
62
-     */
63
-    @Override
64
-    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
65
-        if(this.isLoginRequest(request, response))
66
-            return true;
67
-
68
-        boolean allowed = false;
69
-        try {
70
-            allowed = executeLogin(request, response);
71
-        } catch(IllegalStateException e){ //not found any token
72
-            log.error("Not found any token", e);
73
-        }catch (Exception e) {
74
-            log.error("Error occurs when login", e);
75
-        }
76
-        return allowed;// || super.isPermissive(mappedValue);
77
-    }
78
-
79
-    /**
80
-          * 这里重写了父类的方法,使用我们自己定义的Token类,提交给shiro。这个方法返回null的话会直接抛出异常,进入isAccessAllowed()的异常处理逻辑。
81
-     */
82
-    @Override
83
-    protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) {
84
-        String jwtToken = getAuthzHeader(servletRequest);
85
-        if(!StringUtils.isEmpty(jwtToken)&&!JwtUtils.isTokenExpired(jwtToken))
86
-            return new JWTToken(jwtToken);
87
-
88
-        return null;
89
-    }
90
-
91
-    @Override
92
-    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
93
-        
94
-    	HttpServletRequest httpServletRequest = WebUtils.toHttp(servletRequest);
95
-        HttpServletResponse httpResponse = WebUtils.toHttp(servletResponse);
96
-        // 返回401
97
-        httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
98
-        httpResponse.getOutputStream().println("401 UNAUTHORIZED");
99
-        // 设置响应码为401或者直接输出消息
100
-        String url = httpServletRequest.getRequestURI();
101
-        log.error("onAccessDenied url:{}", url);
102
-
103
-    	return false;
104
-    }
105
-
106
-    /**
107
-          *  如果Shiro Login认证成功,会进入该方法,等同于用户名密码登录成功,我们这里还判断了是否要刷新Token
108
-     */
109
-    @Override
110
-    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
111
-        HttpServletResponse httpResponse = WebUtils.toHttp(response);
112
-        String newToken = null;
113
-        if(token instanceof JWTToken){
114
-            JWTToken jwtToken = (JWTToken)token;
115
-            UserDto user = (UserDto) subject.getPrincipal();
116
-            boolean shouldRefresh = shouldTokenRefresh(JwtUtils.getIssuedAt(jwtToken.getToken()));
117
-            if(shouldRefresh) {
118
-                newToken = userService.generateJwtToken(user.getUsername());
119
-            }
120
-        }
121
-        if(!StringUtils.isEmpty(newToken))
122
-            httpResponse.setHeader("x-auth-token", newToken);
123
-
124
-        return true;
125
-    }
126
-
127
-    @Override
128
-    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
129
-        log.error("Validate token fail, token:{}, error:{}", token.toString(), e.getMessage());
130
-        return false;
131
-    }
132
-
133
-    protected String getAuthzHeader(ServletRequest request) {
134
-        HttpServletRequest httpRequest = WebUtils.toHttp(request);
135
-        String header = httpRequest.getHeader("x-auth-token");
136
-        if (StringUtils.startsWithIgnoreCase(header, "Bearer ")) {
137
-			return StringUtils.replace(header, "Bearer ", "");
138
-		}
139
-        return header;
140
-    }
141
-
142
-    protected boolean shouldTokenRefresh(Date issueAt){
143
-        LocalDateTime issueTime = LocalDateTime.ofInstant(issueAt.toInstant(), ZoneId.systemDefault());
144
-        return LocalDateTime.now().minusSeconds(tokenRefreshInterval).isAfter(issueTime);
145
-    }
146
-
147
-    protected void fillCorsHeader(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse){
148
-        httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
149
-        httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,HEAD");
150
-        httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
151
-    }
152
-}

+ 0 - 41
spring5-auth/spring5-auth-client/src/main/java/com/yaozhitech/spring5/jwt/JWTCredentialsMatcher.java

@@ -1,41 +0,0 @@
1
-package com.yaozhitech.spring5.jwt;
2
-
3
-import java.io.UnsupportedEncodingException;
4
-
5
-import org.apache.shiro.authc.AuthenticationInfo;
6
-import org.apache.shiro.authc.AuthenticationToken;
7
-import org.apache.shiro.authc.credential.CredentialsMatcher;
8
-
9
-import com.auth0.jwt.JWT;
10
-import com.auth0.jwt.JWTVerifier;
11
-import com.auth0.jwt.algorithms.Algorithm;
12
-import com.auth0.jwt.exceptions.JWTVerificationException;
13
-import com.yaozhitech.spring5.dto.UserDto;
14
-
15
-import lombok.extern.slf4j.Slf4j;
16
-
17
-@Slf4j
18
-public class JWTCredentialsMatcher implements CredentialsMatcher {
19
-	
20
-    @Override
21
-    public boolean doCredentialsMatch(AuthenticationToken authenticationToken, AuthenticationInfo authenticationInfo) {
22
-        String token = (String) authenticationToken.getCredentials();
23
-        Object stored = authenticationInfo.getCredentials();
24
-        String salt = stored.toString();
25
-
26
-        UserDto user = (UserDto)authenticationInfo.getPrincipals().getPrimaryPrincipal();
27
-        try {
28
-            Algorithm algorithm = Algorithm.HMAC256(salt);
29
-            JWTVerifier verifier = JWT.require(algorithm)
30
-                    .withClaim("username", user.getUsername())
31
-                    .build();
32
-            verifier.verify(token);
33
-            return true;
34
-        } catch (UnsupportedEncodingException | JWTVerificationException e) {
35
-            log.error("Token Error:{}", e.getMessage());
36
-        }
37
-
38
-        return false;
39
-    }
40
-
41
-}

+ 0 - 58
spring5-auth/spring5-auth-client/src/main/java/com/yaozhitech/spring5/jwt/JWTShiroRealm.java

@@ -1,58 +0,0 @@
1
-package com.yaozhitech.spring5.jwt;
2
-
3
-import org.apache.shiro.authc.AuthenticationException;
4
-import org.apache.shiro.authc.AuthenticationInfo;
5
-import org.apache.shiro.authc.AuthenticationToken;
6
-import org.apache.shiro.authc.SimpleAuthenticationInfo;
7
-import org.apache.shiro.authz.AuthorizationInfo;
8
-import org.apache.shiro.authz.SimpleAuthorizationInfo;
9
-import org.apache.shiro.realm.AuthorizingRealm;
10
-import org.apache.shiro.subject.PrincipalCollection;
11
-
12
-import com.yaozhitech.spring5.dto.UserDto;
13
-import com.yaozhitech.spring5.service.JwtUserService;
14
-import com.yaozhitech.spring5.utils.JwtUtils;
15
-
16
-
17
-/**
18
- * 自定义身份认证
19
- * 基于HMAC( 散列消息认证码)的控制域
20
- */
21
-
22
-public class JWTShiroRealm extends AuthorizingRealm {
23
-
24
-    protected JwtUserService userService;
25
-
26
-    public JWTShiroRealm(JwtUserService userService){
27
-        this.userService = userService;
28
-        this.setCredentialsMatcher(new JWTCredentialsMatcher());
29
-    }
30
-
31
-    @Override
32
-    public boolean supports(AuthenticationToken token) {
33
-        return token instanceof JWTToken;
34
-    }
35
-
36
-    /**
37
-     * 认证信息.(身份验证) : Authentication 是用来验证用户身份
38
-     * 默认使用此方法进行用户名正确与否验证,错误抛出异常即可。
39
-     */
40
-    @Override
41
-    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {    
42
-        JWTToken jwtToken = (JWTToken) authcToken;
43
-        String token = jwtToken.getToken();
44
-        
45
-        UserDto user = userService.getJwtTokenInfo(JwtUtils.getUsername(token));
46
-        if(user == null)
47
-            throw new AuthenticationException("token过期,请重新登录");
48
-
49
-        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getSalt(), "jwtRealm");
50
-
51
-        return authenticationInfo;
52
-    }
53
-
54
-    @Override
55
-    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
56
-        return new SimpleAuthorizationInfo();
57
-    }
58
-}

+ 0 - 44
spring5-auth/spring5-auth-client/src/main/java/com/yaozhitech/spring5/jwt/JWTToken.java

@@ -1,44 +0,0 @@
1
-package com.yaozhitech.spring5.jwt;
2
-
3
-import org.apache.shiro.authc.HostAuthenticationToken;
4
-
5
-import lombok.Data;
6
-
7
-@Data
8
-public class JWTToken implements HostAuthenticationToken {
9
-
10
-	/**
11
-	 * 
12
-	 */
13
-	private static final long serialVersionUID = -6910437116441110747L;
14
-	
15
-	private String token;
16
-    private String host;
17
-    
18
-    public JWTToken(String token) {
19
-        this(token, null);
20
-    }
21
-
22
-    public JWTToken(String token, String host) {
23
-        this.token = token;
24
-        this.host = host;
25
-    }
26
-    
27
-	@Override
28
-	public Object getPrincipal() {
29
-		return token;
30
-	}
31
-	@Override
32
-	public Object getCredentials() {
33
-		return token;
34
-	}
35
-	@Override
36
-	public String getHost() {
37
-		return host;
38
-	}
39
-    
40
-	@Override
41
-    public String toString(){
42
-        return token + ':' + host;
43
-    }
44
-}

+ 0 - 82
spring5-auth/spring5-auth-client/src/main/java/com/yaozhitech/spring5/service/JwtUserService.java

@@ -1,82 +0,0 @@
1
-package com.yaozhitech.spring5.service;
2
-
3
-import java.time.Duration;
4
-import java.util.Arrays;
5
-import java.util.List;
6
-
7
-import org.apache.shiro.crypto.hash.Sha256Hash;
8
-import org.springframework.beans.factory.annotation.Autowired;
9
-import org.springframework.beans.factory.annotation.Value;
10
-import org.springframework.data.redis.core.StringRedisTemplate;
11
-import org.springframework.stereotype.Service;
12
-
13
-import com.yaozhitech.spring5.dto.UserDto;
14
-import com.yaozhitech.spring5.utils.JwtUtils;
15
-
16
-@Service
17
-public class JwtUserService {
18
-
19
-	@Value("${password.salt}")
20
-	private String encryptSalt;
21
-
22
-	@Autowired
23
-	private StringRedisTemplate redisTemplate;
24
-
25
-	/**
26
-	 * 保存user登录信息,返回token
27
-	 * 
28
-	 * @param userDto
29
-	 */
30
-	public String generateJwtToken(String username) {
31
-		String salt = JwtUtils.generateSalt();
32
-		redisTemplate.opsForValue().set("token:"+username, salt, Duration.ofSeconds(3600));
33
-		return JwtUtils.sign(username, salt, 3600); // 生成jwt token,设置过期时间为1小时
34
-	}
35
-
36
-	/**
37
-	 * 获取上次token生成时的salt值和登录用户信息
38
-	 * 
39
-	 * @param username
40
-	 * @return
41
-	 */
42
-	public UserDto getJwtTokenInfo(String username) {
43
-		String salt = redisTemplate.opsForValue().get("token:"+username);
44
-		UserDto user = getUserInfo(username);
45
-		user.setSalt(salt);
46
-		return user;
47
-	}
48
-
49
-	/**
50
-	 * 清除token信息
51
-	 * 
52
-	 * @param userName 登录用户名
53
-	 * @param terminal 登录终端
54
-	 */
55
-	public void deleteLoginInfo(String username) {
56
-		redisTemplate.delete("token:"+username);
57
-	}
58
-
59
-	/**
60
-	 * 获取数据库中保存的用户信息,主要是加密后的密码
61
-	 * 
62
-	 * @param userName
63
-	 * @return
64
-	 */
65
-	public UserDto getUserInfo(String userName) {
66
-		UserDto user = new UserDto();
67
-		user.setUserId(1L);
68
-		user.setUsername("admin");
69
-		user.setEncryptPwd(new Sha256Hash("123456", encryptSalt).toHex());
70
-		return user;
71
-	}
72
-
73
-	/**
74
-	 * 获取用户角色列表,强烈建议从缓存中获取
75
-	 * 
76
-	 * @param userId
77
-	 * @return
78
-	 */
79
-	public List<String> getUserRoles(Long userId) {
80
-		return Arrays.asList("admin");
81
-	}
82
-}

+ 37 - 5
spring5-auth/spring5-auth-client/src/main/java/com/yaozhitech/spring5/utils/JwtUtils.java

@@ -3,14 +3,19 @@ package com.yaozhitech.spring5.utils;
3 3
 import java.io.UnsupportedEncodingException;
4 4
 import java.util.Calendar;
5 5
 import java.util.Date;
6
-
7
-import org.apache.shiro.crypto.SecureRandomNumberGenerator;
6
+import java.util.Map;
8 7
 
9 8
 import com.auth0.jwt.JWT;
9
+import com.auth0.jwt.JWTVerifier;
10 10
 import com.auth0.jwt.algorithms.Algorithm;
11 11
 import com.auth0.jwt.exceptions.JWTDecodeException;
12
+import com.auth0.jwt.interfaces.Claim;
12 13
 import com.auth0.jwt.interfaces.DecodedJWT;
14
+import com.yaozhitech.spring5.common.util.UUIDUtils;
15
+
16
+import lombok.extern.slf4j.Slf4j;
13 17
 
18
+@Slf4j
14 19
 public class JwtUtils {
15 20
 
16 21
 	/**
@@ -22,6 +27,7 @@ public class JwtUtils {
22 27
             DecodedJWT jwt = JWT.decode(token);
23 28
             return jwt.getIssuedAt();
24 29
         } catch (JWTDecodeException e) {
30
+        	log.error(e.getMessage(), e);
25 31
             return null;
26 32
         }
27 33
     }
@@ -35,8 +41,36 @@ public class JwtUtils {
35 41
             DecodedJWT jwt = JWT.decode(token);
36 42
             return jwt.getClaim("username").asString();
37 43
         } catch (JWTDecodeException e) {
44
+        	log.error(e.getMessage(), e);
45
+            return null;
46
+        }
47
+    }
48
+    
49
+    /**
50
+     * 需要密钥才能获得信息
51
+     */
52
+    public static Map<String, Claim> verifyToken(String token, String secret) {
53
+        DecodedJWT jwt = null;
54
+        try {
55
+            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(secret)).build();
56
+            jwt = verifier.verify(token);
57
+        } catch (Exception e) {
58
+        	log.error(e.getMessage(), e);
59
+            return null;
60
+        }
61
+        return jwt.getClaims();
62
+    }
63
+    
64
+    public static String verifyTokenAndGet(String token, String secret) {
65
+        DecodedJWT jwt = null;
66
+        try {
67
+            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(secret)).build();
68
+            jwt = verifier.verify(token);
69
+        } catch (Exception e) {
70
+        	log.error(e.getMessage(), e);
38 71
             return null;
39 72
         }
73
+        return jwt.getClaim("username").asString();
40 74
     }
41 75
 
42 76
     /**
@@ -75,8 +109,6 @@ public class JwtUtils {
75 109
      * @return
76 110
      */
77 111
     public static String generateSalt(){
78
-        SecureRandomNumberGenerator secureRandom = new SecureRandomNumberGenerator();
79
-        String hex = secureRandom.nextBytes(16).toHex();
80
-        return hex;
112
+        return UUIDUtils.generateShortUuid();
81 113
     }
82 114
 }

+ 2 - 0
spring5-auth/spring5-auth-client/src/main/resources/application.yml

@@ -0,0 +1,2 @@
1
+jwt:
2
+  salt: xP3La8IhZjl4fmWXD.AYVH5tor5bn-Rr

+ 0 - 25
spring5-order/src/main/java/com/yaozhitech/spring5/config/RoleResourceConfiguration.java

@@ -1,25 +0,0 @@
1
-package com.yaozhitech.spring5.config;
2
-
3
-import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
4
-import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
5
-import org.springframework.context.annotation.Configuration;
6
-
7
-@Configuration
8
-public class RoleResourceConfiguration extends ShiroConfiguration{
9
-	
10
-	@Override
11
-	public ShiroFilterChainDefinition shiroFilterChainDefinition() {
12
-		
13
-		
14
-		DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
15
-//    chainDefinition.addPathDefinition("/login", "noSessionCreation,anon");  //login不做认证,noSessionCreation的作用是用户在操作session时会抛异常
16
-//    chainDefinition.addPathDefinition("/logout", "noSessionCreation,authcToken[permissive]"); //做用户认证,permissive参数的作用是当token无效时也允许请求访问,不会返回鉴权未通过的错误
17
-//    chainDefinition.addPathDefinition("/image/**", "anon"); ,anyRole[admin,manager]
18
-		chainDefinition.addPathDefinition("/**", "anon"); // 只允许admin或manager角色的用户访问
19
-//		chainDefinition.addPathDefinition("/article/list", "noSessionCreation,authc");
20
-//		chainDefinition.addPathDefinition("/article/*", "noSessionCreation,authc[permissive]");
21
-//		chainDefinition.addPathDefinition("/**", "noSessionCreation,authc"); // 默认进行用户鉴权
22
-		
23
-		return chainDefinition;
24
-	}
25
-}

+ 16 - 1
spring5-order/src/main/java/com/yaozhitech/spring5/controller/OrderController.java

@@ -12,6 +12,9 @@ import com.yaozhitech.spring5.annotation.IgnoreClientToken;
12 12
 import com.yaozhitech.spring5.provider.AdminProvider;
13 13
 import com.yaozhitech.spring5.utils.JwtUtils;
14 14
 
15
+import lombok.extern.slf4j.Slf4j;
16
+
17
+@Slf4j
15 18
 @RestController
16 19
 @RequestMapping("/order")
17 20
 public class OrderController {
@@ -24,6 +27,9 @@ public class OrderController {
24 27
 	
25 28
 	@Value("${auth.client.secret}")
26 29
     private String clientSecret;
30
+	
31
+	@Value("$jwt.salt}")
32
+	private String jwtSalt;
27 33
 
28 34
 	@GetMapping("/{id}")
29 35
 	public ResponseEntity<String> read(@PathVariable Long id) {
@@ -33,6 +39,15 @@ public class OrderController {
33 39
 	@IgnoreClientToken
34 40
 	@GetMapping("/token")
35 41
 	public ResponseEntity<String> token() {
36
-		return ResponseEntity.ok(JwtUtils.sign(applicationName + "." + clientSecret, JwtUtils.generateSalt(), 3600));
42
+		String token = JwtUtils.sign(applicationName + "." + clientSecret, jwtSalt, 3600);
43
+		
44
+		String decodeToken = JwtUtils.getUsername(token);
45
+		log.info(decodeToken);
46
+		
47
+		decodeToken = JwtUtils.verifyTokenAndGet("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NzY3NTgzMjUsImlhdCI6MTU3Njc1NDcyNSwidXNlcm5hbWUiOiJvcmRlci5xeDRNWFZSOVNKbTMxcTJDIn0.W_1wgNjhIfB-3D_v7qhqlpxzc2setbAtHo0Iich_GFc",
48
+				jwtSalt);
49
+		log.info(decodeToken);
50
+		
51
+		return ResponseEntity.ok(token);
37 52
 	}
38 53
 }