commit
						1ef676f9ae
					
				
				 23 changed files with 649 additions and 0 deletions
			
			
		| @ -0,0 +1,3 @@ | |||||||
|  | *.iml | ||||||
|  | .idea | ||||||
|  | target | ||||||
| @ -0,0 +1,77 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <project xmlns="http://maven.apache.org/POM/4.0.0" | ||||||
|  |          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||||
|  |          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||||
|  |     <modelVersion>4.0.0</modelVersion> | ||||||
|  | 
 | ||||||
|  |     <parent> | ||||||
|  |         <groupId>org.springframework.boot</groupId> | ||||||
|  |         <artifactId>spring-boot-starter-parent</artifactId> | ||||||
|  |         <version>2.4.6</version> | ||||||
|  |         <relativePath/> | ||||||
|  |     </parent> | ||||||
|  | 
 | ||||||
|  |     <groupId>org.anyin.gitee.shiro</groupId> | ||||||
|  |     <artifactId>shiro-to-token</artifactId> | ||||||
|  |     <version>1.0-SNAPSHOT</version> | ||||||
|  | 
 | ||||||
|  |     <properties> | ||||||
|  |         <spring.boot.version>2.4.6</spring.boot.version> | ||||||
|  |         <spring.boot.shiro.version>1.8.0</spring.boot.shiro.version> | ||||||
|  |         <hutool.version>5.7.2</hutool.version> | ||||||
|  |     </properties> | ||||||
|  | 
 | ||||||
|  |     <dependencies> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>cn.hutool</groupId> | ||||||
|  |             <artifactId>hutool-all</artifactId> | ||||||
|  |             <version>${hutool.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>org.apache.shiro</groupId> | ||||||
|  |             <artifactId>shiro-spring-boot-web-starter</artifactId> | ||||||
|  |             <version>${spring.boot.shiro.version}</version> | ||||||
|  |         </dependency> | ||||||
|  | 
 | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>org.projectlombok</groupId> | ||||||
|  |             <artifactId>lombok</artifactId> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>org.springframework.boot</groupId> | ||||||
|  |             <artifactId>spring-boot-starter-web</artifactId> | ||||||
|  |         </dependency> | ||||||
|  |     </dependencies> | ||||||
|  | 
 | ||||||
|  |     <dependencyManagement> | ||||||
|  |         <dependencies> | ||||||
|  |             <dependency> | ||||||
|  |                 <groupId>org.springframework.boot</groupId> | ||||||
|  |                 <artifactId>spring-boot-dependencies</artifactId> | ||||||
|  |                 <version>${spring.boot.version}</version> | ||||||
|  |                 <type>pom</type> | ||||||
|  |                 <scope>import</scope> | ||||||
|  |             </dependency> | ||||||
|  |         </dependencies> | ||||||
|  |     </dependencyManagement> | ||||||
|  | 
 | ||||||
|  |     <build> | ||||||
|  |         <finalName>shiro-to-token</finalName> | ||||||
|  | 
 | ||||||
|  |         <plugins> | ||||||
|  |             <plugin> | ||||||
|  |                 <groupId>org.springframework.boot</groupId> | ||||||
|  |                 <artifactId>spring-boot-maven-plugin</artifactId> | ||||||
|  |             </plugin> | ||||||
|  |             <plugin> | ||||||
|  |                 <groupId>org.apache.maven.plugins</groupId> | ||||||
|  |                 <artifactId>maven-compiler-plugin</artifactId> | ||||||
|  |                 <configuration> | ||||||
|  |                     <source>1.8</source> | ||||||
|  |                     <target>1.8</target> | ||||||
|  |                     <encoding>UTF-8</encoding> | ||||||
|  |                 </configuration> | ||||||
|  |             </plugin> | ||||||
|  |         </plugins> | ||||||
|  |     </build> | ||||||
|  | </project> | ||||||
| @ -0,0 +1,12 @@ | |||||||
|  | package org.anyin.gitee.shiro; | ||||||
|  | 
 | ||||||
|  | import org.springframework.boot.SpringApplication; | ||||||
|  | import org.springframework.boot.autoconfigure.SpringBootApplication; | ||||||
|  | 
 | ||||||
|  | @SpringBootApplication | ||||||
|  | public class ShiroApplication { | ||||||
|  | 
 | ||||||
|  |     public static void main(String[] args){ | ||||||
|  |         SpringApplication.run(ShiroApplication.class, args); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,24 @@ | |||||||
|  | package org.anyin.gitee.shiro.base; | ||||||
|  | 
 | ||||||
|  | import lombok.Getter; | ||||||
|  | 
 | ||||||
|  | @Getter | ||||||
|  | public enum BusinessCodeEnum { | ||||||
|  |     USER_UN_LOGIN("1008", "用户未登录"), | ||||||
|  |     USER_NOT_FOUND("B1001", "用户账号密码错误"), | ||||||
|  |     PWD_NOT_MATCH("B1002", "用户账号密码错误"), | ||||||
|  |     TOKEN_INVALID("B1003", "Token失效") | ||||||
|  |     ; | ||||||
|  | 
 | ||||||
|  |     private final String code; | ||||||
|  |     private final String msg; | ||||||
|  | 
 | ||||||
|  |     BusinessCodeEnum(String code, String msg) { | ||||||
|  |         this.code = code; | ||||||
|  |         this.msg = msg; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public BusinessException getException(){ | ||||||
|  |         return new BusinessException(this.code, this.msg); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,21 @@ | |||||||
|  | package org.anyin.gitee.shiro.base; | ||||||
|  | 
 | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class BusinessException extends RuntimeException{ | ||||||
|  | 
 | ||||||
|  |     private String code; | ||||||
|  | 
 | ||||||
|  |     private String msg; | ||||||
|  | 
 | ||||||
|  |     public BusinessException(BusinessCodeEnum business){ | ||||||
|  |         this.code = business.getCode(); | ||||||
|  |         this.msg = business.getMsg(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public BusinessException(String code, String msg){ | ||||||
|  |         this.code = code; | ||||||
|  |         this.msg = code; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,30 @@ | |||||||
|  | package org.anyin.gitee.shiro.base; | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.annotation.JsonInclude; | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class Response<T> { | ||||||
|  | 
 | ||||||
|  |     private static final String SUCCESS_CODE = "200"; | ||||||
|  | 
 | ||||||
|  |     private String code; | ||||||
|  | 
 | ||||||
|  |     private String msg; | ||||||
|  | 
 | ||||||
|  |     private T data; | ||||||
|  | 
 | ||||||
|  |     public Response(){ | ||||||
|  |         this.code = SUCCESS_CODE; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Response(T data){ | ||||||
|  |         this.data = data; | ||||||
|  |         this.code = SUCCESS_CODE; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Response(String code, String msg){ | ||||||
|  |         this.code = code; | ||||||
|  |         this.msg = msg; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,22 @@ | |||||||
|  | package org.anyin.gitee.shiro.base; | ||||||
|  | 
 | ||||||
|  | import cn.hutool.extra.spring.SpringUtil; | ||||||
|  | import org.springframework.beans.BeansException; | ||||||
|  | import org.springframework.context.ApplicationContext; | ||||||
|  | import org.springframework.context.ApplicationContextAware; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | 
 | ||||||
|  | @Component | ||||||
|  | public class SpringContext implements ApplicationContextAware { | ||||||
|  | 
 | ||||||
|  |     private static ApplicationContext context = null; | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { | ||||||
|  |         SpringContext.context = applicationContext; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static <T> T getBean(Class<T> type) { | ||||||
|  |         return context.getBean(type); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,64 @@ | |||||||
|  | package org.anyin.gitee.shiro.config; | ||||||
|  | 
 | ||||||
|  | import org.anyin.gitee.shiro.shiro.TokenCredentialsMatcher; | ||||||
|  | import org.anyin.gitee.shiro.shiro.TokenFilter; | ||||||
|  | import org.anyin.gitee.shiro.shiro.TokenRealm; | ||||||
|  | import org.apache.shiro.authc.credential.CredentialsMatcher; | ||||||
|  | import org.apache.shiro.authc.credential.HashedCredentialsMatcher; | ||||||
|  | import org.apache.shiro.crypto.hash.Sha256Hash; | ||||||
|  | import org.apache.shiro.mgt.SessionsSecurityManager; | ||||||
|  | import org.apache.shiro.spring.web.ShiroFilterFactoryBean; | ||||||
|  | import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition; | ||||||
|  | import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition; | ||||||
|  | import org.apache.shiro.web.filter.mgt.DefaultFilter; | ||||||
|  | import org.apache.shiro.web.mgt.DefaultWebSecurityManager; | ||||||
|  | import org.springframework.context.annotation.Bean; | ||||||
|  | import org.springframework.context.annotation.Configuration; | ||||||
|  | 
 | ||||||
|  | import javax.servlet.Filter; | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.LinkedHashMap; | ||||||
|  | import java.util.Map; | ||||||
|  | 
 | ||||||
|  | @Configuration | ||||||
|  | public class ShiroConfig { | ||||||
|  | 
 | ||||||
|  |     @Bean | ||||||
|  |     public TokenRealm tokenRealm(){ | ||||||
|  |         TokenRealm realm = new TokenRealm(); | ||||||
|  |         realm.setCredentialsMatcher(credentialsMatcher()); | ||||||
|  |         return realm; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Bean(name = "shiroFilterFactoryBean") | ||||||
|  |     public ShiroFilterFactoryBean shiroFilterFactoryBean(){ | ||||||
|  |         // 认证过滤器
 | ||||||
|  |         Map<String, Filter> filterMap = new HashMap<>(); | ||||||
|  |         filterMap.put("token", new TokenFilter()); | ||||||
|  | 
 | ||||||
|  |         // 忽略路径
 | ||||||
|  |         Map<String, String>  filterChainDefinitionMap = new LinkedHashMap<>(); | ||||||
|  |         filterChainDefinitionMap.put("/login", DefaultFilter.anon.name()); | ||||||
|  |         filterChainDefinitionMap.put("/logout", DefaultFilter.anon.name()); | ||||||
|  |         filterChainDefinitionMap.put("/**", "token"); | ||||||
|  | 
 | ||||||
|  |         // 装配bean
 | ||||||
|  |         ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean(); | ||||||
|  |         filterFactoryBean.setSecurityManager(securityManager()); | ||||||
|  |         filterFactoryBean.setFilters(filterMap); | ||||||
|  |         filterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); | ||||||
|  |         return filterFactoryBean; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Bean | ||||||
|  |     public CredentialsMatcher credentialsMatcher(){ | ||||||
|  |         return new TokenCredentialsMatcher(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Bean | ||||||
|  |     public SessionsSecurityManager securityManager() { | ||||||
|  |         DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); | ||||||
|  |         securityManager.setRealm(tokenRealm()); | ||||||
|  |         return securityManager; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,16 @@ | |||||||
|  | package org.anyin.gitee.shiro.controller; | ||||||
|  | 
 | ||||||
|  | import org.anyin.gitee.shiro.base.Response; | ||||||
|  | import org.springframework.web.bind.annotation.GetMapping; | ||||||
|  | import org.springframework.web.bind.annotation.RequestMapping; | ||||||
|  | import org.springframework.web.bind.annotation.RestController; | ||||||
|  | 
 | ||||||
|  | @RestController | ||||||
|  | @RequestMapping("/home") | ||||||
|  | public class HomeController { | ||||||
|  | 
 | ||||||
|  |     @GetMapping | ||||||
|  |     public Response<String> home(){ | ||||||
|  |         return new Response<>("success"); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,30 @@ | |||||||
|  | package org.anyin.gitee.shiro.controller; | ||||||
|  | 
 | ||||||
|  | import org.anyin.gitee.shiro.base.Response; | ||||||
|  | import org.anyin.gitee.shiro.controller.form.LoginForm; | ||||||
|  | import org.anyin.gitee.shiro.model.UserInfo; | ||||||
|  | import org.anyin.gitee.shiro.service.ILoginService; | ||||||
|  | import org.springframework.beans.factory.annotation.Autowired; | ||||||
|  | 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; | ||||||
|  | 
 | ||||||
|  | @RestController | ||||||
|  | @RequestMapping | ||||||
|  | public class LoginController { | ||||||
|  | 
 | ||||||
|  |     @Autowired | ||||||
|  |     private ILoginService loginService; | ||||||
|  | 
 | ||||||
|  |     @PostMapping("/login") | ||||||
|  |     public Response<String> login(@RequestBody LoginForm form){ | ||||||
|  |         String token = loginService.login(form.getUsername(), form.getPassword()); | ||||||
|  |         return new Response<>(token); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @PostMapping("/logout") | ||||||
|  |     public Response<String> logout(){ | ||||||
|  |         return new Response<>(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,11 @@ | |||||||
|  | package org.anyin.gitee.shiro.controller.form; | ||||||
|  | 
 | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class LoginForm { | ||||||
|  | 
 | ||||||
|  |     private String username; | ||||||
|  | 
 | ||||||
|  |     private String password; | ||||||
|  | } | ||||||
| @ -0,0 +1,15 @@ | |||||||
|  | package org.anyin.gitee.shiro.model; | ||||||
|  | 
 | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class UserInfo { | ||||||
|  | 
 | ||||||
|  |     private Integer id; | ||||||
|  | 
 | ||||||
|  |     private String username; | ||||||
|  | 
 | ||||||
|  |     private String nickName; | ||||||
|  | 
 | ||||||
|  |     private String password; | ||||||
|  | } | ||||||
| @ -0,0 +1,8 @@ | |||||||
|  | package org.anyin.gitee.shiro.service; | ||||||
|  | 
 | ||||||
|  | public interface ILoginService { | ||||||
|  | 
 | ||||||
|  |     String login(String username, String password); | ||||||
|  | 
 | ||||||
|  |     void logout(String token); | ||||||
|  | } | ||||||
| @ -0,0 +1,15 @@ | |||||||
|  | package org.anyin.gitee.shiro.service; | ||||||
|  | 
 | ||||||
|  | import org.anyin.gitee.shiro.model.UserInfo; | ||||||
|  | import org.anyin.gitee.shiro.shiro.ShiroToken; | ||||||
|  | 
 | ||||||
|  | public interface ITokenService { | ||||||
|  | 
 | ||||||
|  |     boolean check(String token); | ||||||
|  | 
 | ||||||
|  |     ShiroToken createToken(String token, UserInfo userInfo); | ||||||
|  | 
 | ||||||
|  |     ShiroToken createToken(UserInfo userInfo); | ||||||
|  | 
 | ||||||
|  |     UserInfo getUserInfo(String token); | ||||||
|  | } | ||||||
| @ -0,0 +1,8 @@ | |||||||
|  | package org.anyin.gitee.shiro.service; | ||||||
|  | 
 | ||||||
|  | import org.anyin.gitee.shiro.model.UserInfo; | ||||||
|  | 
 | ||||||
|  | public interface IUserInfoService { | ||||||
|  | 
 | ||||||
|  |     UserInfo findByUsername(String username); | ||||||
|  | } | ||||||
| @ -0,0 +1,41 @@ | |||||||
|  | package org.anyin.gitee.shiro.service.impl; | ||||||
|  | 
 | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import org.anyin.gitee.shiro.base.BusinessCodeEnum; | ||||||
|  | import org.anyin.gitee.shiro.model.UserInfo; | ||||||
|  | import org.anyin.gitee.shiro.service.ILoginService; | ||||||
|  | import org.anyin.gitee.shiro.service.ITokenService; | ||||||
|  | import org.anyin.gitee.shiro.service.IUserInfoService; | ||||||
|  | import org.anyin.gitee.shiro.shiro.ShiroToken; | ||||||
|  | import org.apache.shiro.SecurityUtils; | ||||||
|  | import org.springframework.beans.factory.annotation.Autowired; | ||||||
|  | import org.springframework.stereotype.Service; | ||||||
|  | 
 | ||||||
|  | @Service | ||||||
|  | @Slf4j | ||||||
|  | public class LoginServiceImpl implements ILoginService { | ||||||
|  | 
 | ||||||
|  |     @Autowired | ||||||
|  |     private IUserInfoService userInfoService; | ||||||
|  | 
 | ||||||
|  |     @Autowired | ||||||
|  |     private ITokenService tokenService; | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String login(String username, String password) { | ||||||
|  |         UserInfo userInfo = userInfoService.findByUsername(username); | ||||||
|  |         if(!userInfo.getPassword().equals(password)){ | ||||||
|  |             throw BusinessCodeEnum.PWD_NOT_MATCH.getException(); | ||||||
|  |         } | ||||||
|  |         // shiro 框架登录
 | ||||||
|  |         ShiroToken token = tokenService.createToken(userInfo); | ||||||
|  |         SecurityUtils.getSubject().login(token); | ||||||
|  | 
 | ||||||
|  |         return (String) token.getCredentials(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void logout(String token) { | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,46 @@ | |||||||
|  | package org.anyin.gitee.shiro.service.impl; | ||||||
|  | 
 | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import org.anyin.gitee.shiro.model.UserInfo; | ||||||
|  | import org.anyin.gitee.shiro.service.ITokenService; | ||||||
|  | import org.anyin.gitee.shiro.shiro.ShiroToken; | ||||||
|  | import org.springframework.stereotype.Service; | ||||||
|  | import org.springframework.util.ObjectUtils; | ||||||
|  | 
 | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.UUID; | ||||||
|  | 
 | ||||||
|  | @Service | ||||||
|  | @Slf4j | ||||||
|  | public class TokenServiceImpl implements ITokenService { | ||||||
|  | 
 | ||||||
|  |     private Map<String, UserInfo> tokenUserMap = new HashMap<>(); | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean check(String token) { | ||||||
|  |         log.info("check token is valid"); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public ShiroToken createToken(String token, UserInfo userInfo) { | ||||||
|  |         String targetToken = token; | ||||||
|  |         if(ObjectUtils.isEmpty(targetToken)){ | ||||||
|  |             targetToken = UUID.randomUUID().toString(); | ||||||
|  |         } | ||||||
|  |         // token 和 用户信息的映射,可以使用Redis存储 或者 替换为JWT
 | ||||||
|  |         tokenUserMap.put(targetToken, userInfo); | ||||||
|  |         return new ShiroToken(targetToken); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public ShiroToken createToken(UserInfo userInfo) { | ||||||
|  |         return this.createToken("", userInfo); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public UserInfo getUserInfo(String token) { | ||||||
|  |         return tokenUserMap.get(token); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,28 @@ | |||||||
|  | package org.anyin.gitee.shiro.service.impl; | ||||||
|  | 
 | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import org.anyin.gitee.shiro.base.BusinessCodeEnum; | ||||||
|  | import org.anyin.gitee.shiro.model.UserInfo; | ||||||
|  | import org.anyin.gitee.shiro.service.IUserInfoService; | ||||||
|  | import org.springframework.stereotype.Service; | ||||||
|  | 
 | ||||||
|  | @Service | ||||||
|  | @Slf4j | ||||||
|  | public class UserInfoServiceImpl implements IUserInfoService { | ||||||
|  | 
 | ||||||
|  |     private static final String DEFAULT_USERNAME = "anyin"; | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public UserInfo findByUsername(String username) { | ||||||
|  |         // 从数据库查询用户信息
 | ||||||
|  |         if(DEFAULT_USERNAME.equals(username)){ | ||||||
|  |             UserInfo userInfo = new UserInfo(); | ||||||
|  |             userInfo.setId(1); | ||||||
|  |             userInfo.setNickName("暗音"); | ||||||
|  |             userInfo.setUsername("anyin"); | ||||||
|  |             userInfo.setPassword("123456"); | ||||||
|  |             return userInfo; | ||||||
|  |         } | ||||||
|  |         throw  BusinessCodeEnum.USER_NOT_FOUND.getException(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,22 @@ | |||||||
|  | package org.anyin.gitee.shiro.shiro; | ||||||
|  | 
 | ||||||
|  | import org.apache.shiro.authc.AuthenticationToken; | ||||||
|  | 
 | ||||||
|  | public class ShiroToken implements AuthenticationToken { | ||||||
|  | 
 | ||||||
|  |     private String token; | ||||||
|  | 
 | ||||||
|  |     public ShiroToken(String token) { | ||||||
|  |         this.token = token; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public Object getPrincipal() { | ||||||
|  |         return token; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public Object getCredentials() { | ||||||
|  |         return token; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,12 @@ | |||||||
|  | package org.anyin.gitee.shiro.shiro; | ||||||
|  | 
 | ||||||
|  | import org.apache.shiro.authc.AuthenticationInfo; | ||||||
|  | import org.apache.shiro.authc.AuthenticationToken; | ||||||
|  | import org.apache.shiro.authc.credential.CredentialsMatcher; | ||||||
|  | 
 | ||||||
|  | public class TokenCredentialsMatcher implements CredentialsMatcher { | ||||||
|  |     @Override | ||||||
|  |     public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { | ||||||
|  |         return token instanceof ShiroToken; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,95 @@ | |||||||
|  | package org.anyin.gitee.shiro.shiro; | ||||||
|  | 
 | ||||||
|  | import cn.hutool.json.JSONUtil; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import org.anyin.gitee.shiro.base.BusinessCodeEnum; | ||||||
|  | import org.anyin.gitee.shiro.base.Response; | ||||||
|  | import org.anyin.gitee.shiro.base.SpringContext; | ||||||
|  | import org.anyin.gitee.shiro.service.ITokenService; | ||||||
|  | import org.apache.shiro.authc.AuthenticationToken; | ||||||
|  | import org.apache.shiro.web.filter.authc.AuthenticatingFilter; | ||||||
|  | import org.springframework.util.ObjectUtils; | ||||||
|  | import org.springframework.web.bind.annotation.RequestMethod; | ||||||
|  | 
 | ||||||
|  | import javax.servlet.ServletRequest; | ||||||
|  | import javax.servlet.ServletResponse; | ||||||
|  | import javax.servlet.http.HttpServletRequest; | ||||||
|  | import javax.servlet.http.HttpServletResponse; | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Slf4j | ||||||
|  | public class TokenFilter extends AuthenticatingFilter { | ||||||
|  | 
 | ||||||
|  |     private static final String X_TOKEN = "X-Token"; | ||||||
|  | 
 | ||||||
|  |     private ITokenService tokenService = null; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 创建Token, 支持自定义Token | ||||||
|  |      */ | ||||||
|  |     @Override | ||||||
|  |     protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception { | ||||||
|  |         String token = this.getToken((HttpServletRequest)servletRequest); | ||||||
|  |         if(ObjectUtils.isEmpty(token)){ | ||||||
|  |             log.error("token is empty"); | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |         return new ShiroToken(token); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 兼容跨域 | ||||||
|  |      */ | ||||||
|  |     @Override | ||||||
|  |     protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { | ||||||
|  |         return ((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception { | ||||||
|  |         HttpServletRequest request = (HttpServletRequest)servletRequest; | ||||||
|  |         HttpServletResponse response = (HttpServletResponse) servletResponse; | ||||||
|  | 
 | ||||||
|  |         String token = this.getToken(request); | ||||||
|  |         if(ObjectUtils.isEmpty(token)){ | ||||||
|  |             this.respUnLogin(request, response); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // 校验Token的有效性
 | ||||||
|  |         if(tokenService == null){ | ||||||
|  |             tokenService = SpringContext.getBean(ITokenService.class); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(!tokenService.check(token)){ | ||||||
|  |             this.respUnLogin(request, response); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // 根据token获取用户信息,会执行 TokenRealm#doGetAuthenticationInfo 方法
 | ||||||
|  |         return executeLogin(servletRequest, servletResponse); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void respUnLogin(HttpServletRequest request, HttpServletResponse response) throws IOException { | ||||||
|  |         response.setContentType("application/json;charset=utf-8"); | ||||||
|  |         response.setHeader("Access-Control-Allow-Credentials", "true"); | ||||||
|  |         response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin")); | ||||||
|  | 
 | ||||||
|  |         Response resp = new Response(BusinessCodeEnum.USER_UN_LOGIN.getCode(), BusinessCodeEnum.USER_UN_LOGIN.getMsg()); | ||||||
|  |         response.getWriter().print(JSONUtil.toJsonStr(resp)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 获取token | ||||||
|  |      * 优先从header获取 | ||||||
|  |      * 如果没有,则从parameter获取 | ||||||
|  |      * @param request request | ||||||
|  |      * @return token | ||||||
|  |      */ | ||||||
|  |     private String getToken(HttpServletRequest request){ | ||||||
|  |         String token = request.getHeader(X_TOKEN); | ||||||
|  |         if(ObjectUtils.isEmpty(token)){ | ||||||
|  |             token = request.getParameter(X_TOKEN); | ||||||
|  |         } | ||||||
|  |         return token; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,46 @@ | |||||||
|  | package org.anyin.gitee.shiro.shiro; | ||||||
|  | 
 | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import org.anyin.gitee.shiro.base.BusinessCodeEnum; | ||||||
|  | import org.anyin.gitee.shiro.model.UserInfo; | ||||||
|  | import org.anyin.gitee.shiro.service.ITokenService; | ||||||
|  | import org.anyin.gitee.shiro.service.IUserInfoService; | ||||||
|  | import org.apache.shiro.authc.AuthenticationException; | ||||||
|  | import org.apache.shiro.authc.AuthenticationInfo; | ||||||
|  | import org.apache.shiro.authc.AuthenticationToken; | ||||||
|  | import org.apache.shiro.authc.SimpleAuthenticationInfo; | ||||||
|  | import org.apache.shiro.authz.AuthorizationInfo; | ||||||
|  | import org.apache.shiro.realm.AuthorizingRealm; | ||||||
|  | import org.apache.shiro.subject.PrincipalCollection; | ||||||
|  | import org.springframework.beans.factory.annotation.Autowired; | ||||||
|  | import org.springframework.context.annotation.Lazy; | ||||||
|  | 
 | ||||||
|  | @Slf4j | ||||||
|  | public class TokenRealm extends AuthorizingRealm { | ||||||
|  | 
 | ||||||
|  |     @Autowired | ||||||
|  |     @Lazy | ||||||
|  |     private ITokenService tokenService; | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean supports(AuthenticationToken token) { | ||||||
|  |         return token instanceof ShiroToken; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { | ||||||
|  |         log.info("user do authorization: {}", principalCollection); | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { | ||||||
|  |         log.info("user do authentication: {}", authenticationToken); | ||||||
|  |         ShiroToken token = (ShiroToken)authenticationToken; | ||||||
|  |         UserInfo userInfo = tokenService.getUserInfo(token.getCredentials().toString()); | ||||||
|  |         if(userInfo == null){ | ||||||
|  |             throw BusinessCodeEnum.TOKEN_INVALID.getException(); | ||||||
|  |         } | ||||||
|  |         return new SimpleAuthenticationInfo(userInfo.getUsername(), userInfo.getPassword(), userInfo.getNickName()); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,3 @@ | |||||||
|  | spring: | ||||||
|  |   application: | ||||||
|  |     name: shiro-to-token | ||||||
					Loading…
					
					
				
		Reference in new issue
	
	 陈景阳
						陈景阳