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
	
	 陈景阳
						陈景阳