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