shiro
三大组件 :
Subject:包含用户操作信息,
SecurityManager:shiro 的核心心脏,安全管理器,用户的登录校验
Realm:数据库用户信息,权限角色验证等
核心方法:
身份验证(getAuthenticationInfo 方法)验证账户和密码,并返回相关信息
权限获取(getAuthorizationInfo 方法) 获取指定身份的权限,并返回相关信息
令牌支持(supports方法)判断该令牌(Token)是否被支持,令牌有很多种类型,例如:HostAuthenticationToken(主机验证令牌),UsernamePasswordToken(账户密码验证令牌)
采用jwt+redis+shiro+springboot 通过 rbca 实现框架搭建
注意:
1. jwt本身就有超时时间为什么还用redis?
jwt无法控制退出后清除token,导致退出后还能拿token登录,且没有请求延长token时效功能,所以交给redis控制,jwt仅作为工具使用
redis存储方式 <userName,token>
虽然违背了 jwt 使用原则,但是基于业务这是更好的选择。
2. shiro 认证AuthenticationInfo 和授权AuthorizationInfo 抛出异常如何通过全局异常处理返回给前端?
全局异常无法捕捉到shiro的异常,只能通过自己的BasicHttpAuthenticationFilter 捕捉进行处理,例如:
public class JwtFilter extends BasicHttpAuthenticationFilter{
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
try {
........
} catch (java.lang.Exception e) {
this.response401(request,response,401,e.getCause().getMessage());
}
}
.......
private void response401(ServletRequest req, ServletResponse resp,int code,String msg) {
try {
HttpServletResponse response = (HttpServletResponse) resp;
response.setHeader("Context-type", "application/json;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
JSONObject jsonObject = new JSONObject();
jsonObject.put("data","");
jsonObject.put("code",code);
jsonObject.put("msg",msg);
PrintWriter out = response.getWriter();
out.print(jsonObject.toJSONString());
out.flush();
out.close();
} catch (java.lang.Exception e) {
}
}
}
3. redis 可以在每次请求都给token重置超时,但在filter里无法注入redisTemplate?
因为生命周期 filter --> servlet 所以在servlet之前,无法将redis注入到容器,只能写好工具类主动获取:
RedisUtil redisUtil = SpringContextUtil.getBean(RedisUtil.class);
4. 每次请求都走 shiro 认证授权,角色权限都要查库,耗费资源,可以缓存到redis
结构

pom
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- 阿里连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!-- mysql依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- mybatis-plus 依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<!-- 代码生成器依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<!-- 代码生成器依赖 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</version>
</dependency>
<!-- shiro+jwt -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.2.0</version>
</dependency>
<!-- lombok 依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- jwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<!-- swagger2 依赖 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- Swagger第三方UI依赖 -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
<!-- 日期处理工具 -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<!-- common -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<!-- common -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.28</version>
</dependency>
</dependencies>
yml
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3307/shiro?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC
username: root
password: phpts
driver-class-name: com.mysql.jdbc.Driver
jackson:
time-zone: Asia/Shanghai
redis:
jedis:
pool:
#最大连接数
max-active: 8
#最大阻塞等待时间(负数表示没限制)
max-wait: -1
#最大空闲
max-idle: 8
#最小空闲
min-idle: 0
#连接超时时间
timeout: 10000
token:
# 在redis中有效时长(分)
life: 10
# 生成token 秘钥
secret: 123
包configs -->mybatisplus
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
return interceptor;
}
}
@Component
public class MyBatisPlusFillTime implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime", new Date(), metaObject);
}
}
---------------------------------
包configs -->RedisConfig
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
@Bean(name = "redisTemplate")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(keySerializer());
redisTemplate.setHashKeySerializer(keySerializer());
redisTemplate.setValueSerializer(valueSerializer());
redisTemplate.setHashValueSerializer(valueSerializer());
return redisTemplate;
}
private RedisSerializer<String> keySerializer(){
return new StringRedisSerializer();
}
private RedisSerializer<Object> valueSerializer(){
return new GenericJackson2JsonRedisSerializer();
}
}
---------------------------------
包configs -->shiro
@Configuration
public class ShiroConfig {
@Bean("getJwtRealm")
public JwtRealm getJwtRealm(){return new JwtRealm();}
@Bean("securityManager")
public DefaultWebSecurityManager securityManager(@Qualifier("getJwtRealm") JwtRealm jwtRealm){
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
manager.setRealm(jwtRealm);
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
manager.setSubjectDAO(subjectDAO);
return manager;
}
@Bean("shiroFilterFactoryBean")
public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
Map<String, Filter> filters = new HashMap<>();
filters.put("jwt", new JwtFilter());
factoryBean.setFilters(filters);
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/doc.html","anon");
filterMap.put("/webjars/**", "anon");
filterMap.put("/druid/**", "anon");
filterMap.put("/app/**", "anon");
filterMap.put("/sys/login", "anon");
filterMap.put("/sys/loginMany", "anon");
filterMap.put("/swagger/**", "anon");
filterMap.put("/v2/api-docs", "anon");
filterMap.put("/swagger-ui.html", "anon");
filterMap.put("/swagger-resources/**", "anon");
filterMap.put("/captcha", "anon");
filterMap.put("/aaa.txt", "anon");
filterMap.put("/**", "jwt");
factoryBean.setFilterChainDefinitionMap(filterMap);
factoryBean.setSecurityManager(securityManager);
return factoryBean;
}
@Bean
protected SessionStorageEvaluator sessionStorageEvaluator(){
DefaultWebSessionStorageEvaluator sessionStorageEvaluator = new DefaultWebSessionStorageEvaluator();
sessionStorageEvaluator.setSessionStorageEnabled(false);
return sessionStorageEvaluator;
}
@Bean
public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
autoProxyCreator.setProxyTargetClass(true);
return autoProxyCreator;
}
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){return new LifecycleBeanPostProcessor();}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("getJwtRealm") JwtRealm jwtRealm) {
SecurityManager manager = securityManager(jwtRealm);
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(manager);
return advisor;
}
}
---------------------------------
包configs -->swagger
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket createRestApi(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.shirojwt.demo.controller"))
.paths(PathSelectors.any())
.build()
.securityContexts(securityContexts())
.securitySchemes(securitySchemes());
}
private List<SecurityContext> securityContexts() {
List<SecurityContext> res = new ArrayList<>();
res.add(getContextByPath("/hello/*"));
return res;
}
private SecurityContext getContextByPath(String pathRegex) {
return SecurityContext.builder().securityReferences(defaultAuthPath())
.forPaths(PathSelectors.regex(pathRegex))
.build();
}
private List<SecurityReference> defaultAuthPath() {
List<SecurityReference> res = new ArrayList<>();
AuthorizationScope scope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] scopes = new AuthorizationScope[1];
scopes[0] = scope;
res.add(new SecurityReference("Authorization",scopes));
return res;
}
private List<ApiKey> securitySchemes() {
List<ApiKey> res = new ArrayList<>();
ApiKey apiKey = new ApiKey("Auth", "Authorization", "Header");
res.add(apiKey);
return res;
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("springboot+shiro+jwt框架接口文档")
.description("springboot+shiro+jwt框架")
.contact(new Contact("john", "http://localhost:8080/doc.html","[email protected]"))
.version("1.0.0")
.build();
}
}
---------------------------------
包configs -->token
@Data
@Component
@ConfigurationProperties(prefix = "token")
public class TokenLife {
private Integer life;
private String secret;
}
---------------------------------
包configs -->web
@Configuration
public class CrossOriginConfig {
@Bean
public CorsFilter corsFilter(){
CorsConfiguration config =new CorsConfiguration();
config.addAllowedOrigin("*");
config.addAllowedOrigin("null");
config.setAllowCredentials(true);
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
---------------------------------
包utils -->exception
@Component
public class ExceptionResponseEntity {
@Getter
private int code;
@Getter
private String message;
public ExceptionResponseEntity() {
}
public ExceptionResponseEntity(int code, String message) {
this.code = code;
this.message = message;
}
}
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler({MyCustomException.class,MyCustomException.class})
public R customExceptionHandler(HttpServletRequest request, final Exception e, HttpServletResponse response) {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
MyCustomException exception = (MyCustomException) e;
log.error("全局异常信息 ex={}", e.getMessage(), e);
return R.fail(exception.getCode(), e.getMessage());
}
@ExceptionHandler(RuntimeException.class)
public R runtimeExceptionHandler(final Exception e, HttpServletResponse response) {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
if(e.getMessage().contains("com.mysql")){
log.info("\n\n SqlException=========== Exception Start ===== \n"+e+"\n "+"SqlException=========== Exception End =====\n\n");
}else {
log.info("\n\n RuntimeException=========== Exception Start ===== \n"+e+"\n "+"RuntimeException=========== Exception End =====\n\n");
}
return R.fail(HttpStatusCode.ERROR.getCode(),e.getMessage());
}
}
@Component
public class MyCustomException extends RuntimeException{
private static final long serialVersionUID = 8863339790253662109L;
@Getter
private int code ;
@Getter
private String message;
public MyCustomException() {
super();
}
public MyCustomException(String message) {
int code =500;
this.message = message;
this.code = code;
}
public MyCustomException(int code,String message) {
this.message = message;
this.code = code;
}
}
---------------------------------
包utils -->init
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if(SpringContextUtil.applicationContext == null){
SpringContextUtil.applicationContext = applicationContext;
}
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static Object getBean(String name){
return getApplicationContext().getBean(name);
}
public static <T> T getBean(Class<T> clazz){
return getApplicationContext().getBean(clazz);
}
public static <T> T getBean(String name,Class<T> clazz){
return getApplicationContext().getBean(name, clazz);
}
}
---------------------------------
包utils -->jwt
public class JwtFilter extends BasicHttpAuthenticationFilter {
@Override
protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
HttpServletRequest req = (HttpServletRequest) request;
String authorization = req.getHeader(AUTHORIZATION_HEADER);
System.out.println("===============filter获取请求头Authorization: "+authorization+"==============================");
return authorization != null;
}
@Override
protected boolean executeLogin(ServletRequest request, ServletResponse response) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String authorization = httpServletRequest.getHeader(AUTHORIZATION_HEADER);
JwtToken token = new JwtToken(authorization);
getSubject(request, response).login(token);
RedisUtil redisUtil = SpringContextUtil.getBean(RedisUtil.class);
TokenLife tokenLife = SpringContextUtil.getBean(TokenLife.class);
redisUtil.expire(JwtTokenUtil.getUsername(authorization),tokenLife.getLife());
return true;
}
@SneakyThrows
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
if (isLoginAttempt(request, response)) {
try {
executeLogin(request, response);
} catch (java.lang.Exception e) {
this.response401(request,response,401,e.getCause().getMessage());
}
}else {
this.response401(request,response,401,"权限不足,缺失token");
}
return true;
}
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws java.lang.Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
httpServletResponse.setStatus(HttpStatus.OK.value());
return false;
}
return super.preHandle(request, response);
}
private void response401(ServletRequest req, ServletResponse resp,int code,String msg) {
try {
HttpServletResponse response = (HttpServletResponse) resp;
response.setHeader("Context-type", "application/json;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
JSONObject jsonObject = new JSONObject();
jsonObject.put("data","");
jsonObject.put("code",code);
jsonObject.put("msg",msg);
PrintWriter out = response.getWriter();
out.print(jsonObject.toJSONString());
out.flush();
out.close();
} catch (java.lang.Exception e) {
}
}
}
public class JwtRealm extends AuthorizingRealm {
@Autowired
private UserInfoService userInfoService;
@Autowired
private RoleAuthService roleAuthService;
@Autowired
private AuthInfoService authInfoService;
@Autowired
private RedisUtil redisUtil;
@Autowired
private TokenLife tokenLife;
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof JwtToken;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("==================用户授权=============");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
UserInfo user = (UserInfo) principalCollection.getPrimaryPrincipal();
UserInfo userInfo = userInfoService.findUserByUsername(user.getUsername());
if(ObjectUtils.isEmpty(userInfo)){
throw new MyCustomException(401,"用户不存在!");
}
Integer roleId = user.getRoleId();
Set<String> roles = new HashSet<>();
roles.add(String.valueOf(roleId));
Set<String> authodKeys = new HashSet<>();
List<RoleAuth> allAuthorList = roleAuthService.list(new QueryWrapper<RoleAuth>().eq("role_id", roleId));
if(CollectionUtils.isNotEmpty(allAuthorList)){
List<Integer> distinctAuthorId = allAuthorList.stream().map(e -> e.getAuthId()).collect(Collectors.toList());
List<AuthInfo> authInfoList = authInfoService.list(new QueryWrapper<AuthInfo>().in("id",distinctAuthorId ));
if(CollectionUtils.isNotEmpty(authInfoList)){
authodKeys = authInfoList.stream().map(e -> e.getAuthKey()).collect(Collectors.toSet());
}
}
info.setRoles(roles);
info.setStringPermissions(authodKeys);
System.out.println("==================授权成功=============");
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("==================token认证=============");
String token = (String) authenticationToken.getPrincipal();
if(StringUtils.isBlank(token)){
throw new MyCustomException(401,"token不存在!");
}
String username = JwtTokenUtil.getUsername(token);
if(StringUtils.isBlank(username)){
throw new MyCustomException(401,"token异常!");
}
boolean verify = JwtTokenUtil.verify(token, tokenLife.getSecret());
if(!verify) {
throw new MyCustomException(401,"token异常!");
}
if(!redisUtil.hasKey(username)){
throw new MyCustomException(401,"token失效!");
}else {
if( !StringUtils.equals( token, redisUtil.get(username).toString() ) ){
throw new MyCustomException(401,"token不一致,校验失败!");
}
}
UserInfo userInfo = userInfoService.findUserByUsername(username);
if(ObjectUtils.isEmpty(userInfo)){
throw new MyCustomException(401,"用户不存在!");
}
return new SimpleAuthenticationInfo(userInfo,token,getName());
}
}
public class JwtToken implements AuthenticationToken {
private String token;
public JwtToken(String token) {
this.token = token;
}
@Override
public Object getPrincipal() {
return token;
}
@Override
public Object getCredentials() {
return token;
}
}
@Component
public class JwtTokenUtil {
private static final String ISSUSER = "john";
private static final String SUBJECT = "subject";
private static final String AUDIENCE = "web-Program";
private static final long EXPIRE_TIME = 43200*1000;
public static String getUsername(String token) {
try {
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim("username").asString();
} catch (JWTDecodeException e) {
return null;
}
}
public static boolean verify(String token, String secret) {
try {
DecodedJWT jwt1 = JWT.decode(token);
String username = jwt1.getClaim("username").asString();
Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier verifier = JWT.require(algorithm)
.withClaim("username", username )
.build();
DecodedJWT jwt = verifier.verify(token);
return true;
} catch (Exception exception) {
return false;
}
}
public static boolean verify(String token, String username, String secret) {
try {
Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier verifier = JWT.require(algorithm)
.withClaim("username", username )
.build();
DecodedJWT jwt = verifier.verify(token);
return true;
} catch (Exception exception) {
return false;
}
}
public static String creatToken(String username,String secret) {
long now = System.currentTimeMillis();
Date nowDate = new Date(now);
Date expireDate = new Date(now+EXPIRE_TIME);
try {
Algorithm algorithm = Algorithm.HMAC256(secret);
Map<String, Object> map = new HashMap<String, Object>();
map.put("alg", "HS256");
map.put("typ", "JWT");
String token = JWT.create()
.withHeader(map)
.withClaim("username", username)
.withClaim("testkey","value")
.withIssuer(ISSUSER)
.withSubject(SUBJECT)
.withAudience(AUDIENCE)
.withIssuedAt(nowDate)
.withExpiresAt(expireDate)
.sign(algorithm);
return token;
} catch (JWTCreationException exception){
exception.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
public static boolean isExpire(String token){
DecodedJWT jwt = JWT.decode(token);
return System.currentTimeMillis() > jwt.getExpiresAt().getTime();
}
}
--------------------------------------------
包utils---->redis
@Component
public class RedisUtil {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public RedisUtil(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
public boolean expire(String key,long time){
try {
if(time>0){
redisTemplate.expire(key, time, TimeUnit.MINUTES);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public long getExpire(String key){
return redisTemplate.getExpire(key,TimeUnit.SECONDS);
}
public boolean hasKey(String key){
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
@SuppressWarnings("unchecked")
public void del(String ... key){
if(key!=null&&key.length>0){
if(key.length==1){
redisTemplate.delete(key[0]);
}else{
redisTemplate.delete(CollectionUtils.arrayToList(key));
}
}
}
public Object get(String key){
return key==null?null:redisTemplate.opsForValue().get(key);
}
public boolean set(String key,Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean set(String key,Object value,long time){
try {
if(time>0){
redisTemplate.opsForValue().set(key, value, time, TimeUnit.MINUTES);
}else{
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public long incr(String key, long delta){
if(delta<0){
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
public long decr(String key, long delta){
if(delta<0){
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
public Object hget(String key,String item){
return redisTemplate.opsForHash().get(key, item);
}
public Map<Object,Object> hmget(String key){
return redisTemplate.opsForHash().entries(key);
}
public boolean hmset(String key, Map<String,Object> map){
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean hmset(String key, Map<String,Object> map, long time){
try {
redisTemplate.opsForHash().putAll(key, map);
if(time>0){
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean hset(String key,String item,Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean hset(String key,String item,Object value,long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if(time>0){
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public void hdel(String key, Object... item){
redisTemplate.opsForHash().delete(key,item);
}
public boolean hHasKey(String key, String item){
return redisTemplate.opsForHash().hasKey(key, item);
}
public double hincr(String key, String item,double by){
return redisTemplate.opsForHash().increment(key, item, by);
}
public double hdecr(String key, String item,double by){
return redisTemplate.opsForHash().increment(key, item,-by);
}
public Set<Object> sGet(String key){
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public boolean sHasKey(String key,Object value){
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public long sSet(String key, Object...values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
public long sSetAndTime(String key,long time,Object...values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if(time>0) {
expire(key, time);
}
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
public long sGetSetSize(String key){
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
public long setRemove(String key, Object ...values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
public List<Object> lGet(String key, long start, long end){
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public long lGetListSize(String key){
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
public Object lGetIndex(String key,long index){
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean lSet(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean lSet(String key, List<Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean lUpdateIndex(String key, long index,Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public long lRemove(String key,long count,Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
public Set keys(String pattern){
return redisTemplate.keys(pattern);
}
public void convertAndSend(String channel, Object message){
redisTemplate.convertAndSend(channel,message);
}
public List<Object> rangeList(String listKey, long start, long end) {
BoundListOperations<String, Object> boundValueOperations = redisTemplate.boundListOps(listKey);
return boundValueOperations.range(start, end);
}
public Object rifhtPop(String listKey){
BoundListOperations<String, Object> boundValueOperations = redisTemplate.boundListOps(listKey);
return boundValueOperations.rightPop();
}
}
------------------------------
包utils---->result
public enum HttpStatusCode {
CONTINUE(100, "Continue"),
SWITCHING_PROTOCOLS(101, "Switching Protocols"),
PROCESSING(102, "Processing"),
CHECKPOINT(103, "Checkpoint"),
OK(200, "OK"),
CREATED(201, "Created"),
ACCEPTED(202, "Accepted"),
NON_AUTHORITATIVE_INFORMATION(203, "Non-Authoritative Information"),
NO_CONTENT(204, "No Content"),
RESET_CONTENT(205, "Reset Content"),
PARTIAL_CONTENT(206, "Partial Content"),
MULTI_STATUS(207, "Multi-Status"),
ALREADY_REPORTED(208, "Already Reported"),
IM_USED(226, "IM Used"),
MULTIPLE_CHOICES(300, "Multiple Choices"),
MOVED_PERMANENTLY(301, "Moved Permanently"),
ERROR(500, "Bad Request"),
FOUND(302, "Found");
@Getter
private int code;
@Getter
private String msg;
HttpStatusCode(int code, String msg){
this.code = code;
this.msg = msg;
}
}
@Data
public class R<T> {
private int code;
private String msg;
private Long total;
private T data;
private long timestamp ;
public R (){
this.timestamp = System.currentTimeMillis();
}
public static <T> R<T> success(T data){
R R1 = new R();
R1.setCode(HttpStatusCode.OK.getCode());
R1.setMsg(HttpStatusCode.OK.getMsg());
R1.setData(data);
return R1;
}
public static <T> R<T> fail(int code, String msg){
R R1 = new R();
R1.setCode(code);
R1.setMsg(msg);
return R1;
}
public static <T> R<T> fail(String msg){
R R1 = new R();
R1.setCode(500);
R1.setMsg(msg);
return R1;
}
}
---------------------------
包----->time
public class DateUtils {
public final static String DATE_PATTERN = "yyyy-MM-dd";
public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
public static String format(Date date) {
return format(date, DATE_PATTERN);
}
public static String format(Date date, String pattern) {
if(date != null){
SimpleDateFormat df = new SimpleDateFormat(pattern);
return df.format(date);
}
return null;
}
public static Date stringToDate(String strDate, String pattern) {
if (StringUtils.isBlank(strDate)){
return null;
}
DateTimeFormatter fmt = DateTimeFormat.forPattern(pattern);
return fmt.parseLocalDateTime(strDate).toDate();
}
public static Date[] getWeekStartAndEnd(int week) {
DateTime dateTime = new DateTime();
LocalDate date = new LocalDate(dateTime.plusWeeks(week));
date = date.dayOfWeek().withMinimumValue();
Date beginDate = date.toDate();
Date endDate = date.plusDays(6).toDate();
return new Date[]{beginDate, endDate};
}
public static Date addDateSeconds(Date date, int seconds) {
DateTime dateTime = new DateTime(date);
return dateTime.plusSeconds(seconds).toDate();
}
public static Date addDateMinutes(Date date, int minutes) {
DateTime dateTime = new DateTime(date);
return dateTime.plusMinutes(minutes).toDate();
}
public static Date addDateHours(Date date, int hours) {
DateTime dateTime = new DateTime(date);
return dateTime.plusHours(hours).toDate();
}
public static Date addDateDays(Date date, int days) {
DateTime dateTime = new DateTime(date);
return dateTime.plusDays(days).toDate();
}
public static Date addDateWeeks(Date date, int weeks) {
DateTime dateTime = new DateTime(date);
return dateTime.plusWeeks(weeks).toDate();
}
public static Date addDateMonths(Date date, int months) {
DateTime dateTime = new DateTime(date);
return dateTime.plusMonths(months).toDate();
}
public static Date addDateYears(Date date, int years) {
DateTime dateTime = new DateTime(date);
return dateTime.plusYears(years).toDate();
}
public static void main(String[] args) {
System.out.println(addDateYears(new Date(),1));
}
}
controller
@Api(tags = "登录管理")
@RestController
public class LoginController {
@Resource
private LoginService loginService;
@ApiOperation(value = "用户登录(账号互相挤模式)")
@PostMapping("/sys/login")
public R login(@RequestBody UserInfo userInfo){
return loginService.login(userInfo);
}
@ApiOperation(value = "用户登录(账号共享模式)")
@PostMapping("/sys/loginMany")
public R loginMany(@RequestBody UserInfo userInfo){
return loginService.loginMany(userInfo);
}
}
== service
public interface LoginService {
R login(UserInfo userInfo);
R loginMany(UserInfo userInfo);
Object logout(Long userid);
}
== impl
@Service
public class LoginServiceImpl implements LoginService {
private final static String SALT = "123";
@Autowired
private UserInfoService userService;
@Autowired
private RedisUtil redisUtil;
@Autowired
private RoleAuthService roleAuthService;
@Autowired
private AuthInfoService authInfoService;
@Resource
private TokenLife tokenLife;
@Override
public R login(UserInfo userInfo) {
UserInfo user = userService.getOne(new QueryWrapper<UserInfo>()
.eq("username", userInfo.getUsername()));
if (user == null) {
return R.fail("用户名或密码不正确!");
}
String pwd = new SimpleHash("md5",userInfo.getPassword(),SALT,2).toHex();
if(!StringUtils.equals(pwd,user.getPassword())){
return R.fail("用户名或密码不正确!");
}
String token = JwtTokenUtil.creatToken(user.getUsername(),tokenLife.getSecret());
redisUtil.del(user.getUsername());
redisUtil.set(user.getUsername(),token,tokenLife.getLife());
user.setPassword(null);
Map<String, Object> roleAndPermission = this.getRoleAndPermission(user);
return R.success(new HashMap(){{
put("user", user);
put("token", token);
put("role", roleAndPermission.get("role"));
put("permission", roleAndPermission.get("permission"));
}});
}
@Override
public R loginMany(UserInfo userInfo) {
UserInfo user = userService.getOne(new QueryWrapper<UserInfo>()
.eq("username", userInfo.getUsername()));
if (user == null) {
return R.fail("用户名或密码不正确!");
}
String pwd = new SimpleHash("md5",userInfo.getPassword(),SALT,2).toHex();
if(!StringUtils.equals(pwd,user.getPassword())){
return R.fail("用户名或密码不正确!");
}
String token = null;
if(redisUtil.hasKey(user.getUsername())){
token = redisUtil.get(user.getUsername()).toString();
}else {
token = JwtTokenUtil.creatToken(user.getUsername(),tokenLife.getSecret());
redisUtil.set(user.getUsername(),token,tokenLife.getLife());
}
String finalToken = token;
user.setPassword(null);
Map<String, Object> roleAndPermission = this.getRoleAndPermission(user);
return R.success(new HashMap(){{
put("user", user);
put("token", finalToken);
put("role", roleAndPermission.get("role"));
put("permission", roleAndPermission.get("permission"));
}}
);
}
@Override
public Object logout(Long userid) {
return null;
}
public Map<String,Object> getRoleAndPermission(UserInfo user) {
Map<String,Object> info = new HashMap<>();
Integer roleId = user.getRoleId();
Set<String> roles = new HashSet<>();
roles.add(String.valueOf(roleId));
Set<String> authodKeys = new HashSet<>();
List<RoleAuth> allAuthorList = roleAuthService.list(new QueryWrapper<RoleAuth>().eq("role_id", roleId));
if(CollectionUtils.isNotEmpty(allAuthorList)){
List<Integer> distinctAuthorId = allAuthorList.stream().map(e -> e.getAuthId()).collect(Collectors.toList());
List<AuthInfo> authInfoList = authInfoService.list(new QueryWrapper<AuthInfo>().in("id",distinctAuthorId ));
if(CollectionUtils.isNotEmpty(authInfoList)){
authodKeys = authInfoList.stream().map(e -> e.getAuthKey()).collect(Collectors.toSet());
}
}
info.put("role",roles);
info.put("permission",authodKeys);
return info;
}
}