概述
这个demo是基于springboot项目的。
名词介绍:
Shiro
主要分为 安全认证 和 接口授权 两个部分,其中的核心组件为 Subject、 SecurityManager、 Realms,公共部分 Shiro 都已经为我们封装好了,我们只需要按照一定的规则去编写响应的代码即可…
Subject
表示主体,将用户的概念理解为当前操作的主体,因为它即可以是一个通过浏览器请求的用户,也可能是一个运行的程序,外部应用与 Subject 进行交互,记录当前操作用户。Subject 代表了当前用户的安全操作
SecurityManager
则管理所有用户的安全操作。
SecurityManager
即安全管理器,对所有的 Subject 进行安全管理,并通过它来提供安全管理的各种服务(认证、授权等)
Realm
充当了应用与数据安全间的 桥梁 或 连接器。当对用户执行认证(登录)和授权(访问控制)验证时,Shiro 会从应用配置的 Realm 中查找用户及其权限信息。
项目结构
1.导入shiro依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--juint-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--starter-web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--connector-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--jdbc的启动器,默认使用HikariCP连接池-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--mybatis_plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.30</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<!--shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>2.8.24</version>
</dependency>
<!--commons-lang3-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<!--swagger 2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
将用户信息交给redis管理
使用swagger2
2.shiro配置类
import com.example.shirospringboot.realm.UserRealm;
import com.example.shirospringboot.shiro.MySessionManager;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* shiro中文学习
* https://www.w3cschool.cn/shiro/xgj31if4.html
*/
/**
* 测试role,permission的时候,手动删除旧的redis键值对
*/
@Configuration
public class ShiroConfig {
@Autowired
private RedisManager redisManager;
@Autowired
private RedisSessionDAO redisSessionDAO;
@Autowired
private RedisCacheManager redisCacheManager;
@Bean()
public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
/**
* 拦截器
* anon: 无需认证就可以访问
* authc: 必须认证才能访问
* user: 必须拥有记住我功能才能用
* perms: 拥有对某个资源的权限才能访问
* role: 拥有某个角色权限才能访问
*/
Map<String, String> filterChainDefinitionMap =new LinkedHashMap<>();
filterChainDefinitionMap.put("/login","anon");
filterChainDefinitionMap.put("/logout","anon");
/**
* 使用权限注解的不需要在这里加,如/test
* filterChainDefinitionMap .put("/test","authc");
*/
//放行Swagger2页面,需要放行这些
filterChainDefinitionMap.put("/swagger-ui.html","anon");
filterChainDefinitionMap.put("/swagger/**","anon");
filterChainDefinitionMap.put("/webjars/**", "anon");
filterChainDefinitionMap.put("/swagger-resources/**","anon");
filterChainDefinitionMap.put("/v2/**","anon");
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap .put("/**","authc");
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setUnauthorizedUrl("/login");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("MD5");//散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashIterations(1024);//散列的次数
hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
return hashedCredentialsMatcher;
}
@Bean()
public UserRealm userRealm() {
UserRealm userRealm = new UserRealm();
userRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return userRealm;
}
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(){
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
defaultWebSecurityManager.setRealm(userRealm());
// 自定义session管理 使用redis
defaultWebSecurityManager.setSessionManager(sessionManager());
// 自定义缓存实现 使用redis
defaultWebSecurityManager.setCacheManager(redisCacheManager);
return defaultWebSecurityManager;
}
@Bean
public SessionManager sessionManager() {
MySessionManager mySessionManager = new MySessionManager();
mySessionManager.setSessionDAO(redisSessionDAO);
return mySessionManager;
}
/**
* 开启shiro权限注解
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
@Bean
public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
autoProxyCreator.setProxyTargetClass(true);
return autoProxyCreator;
}
}
3.ShiroRedis配置类
application.properties
spring.redis.shiro.host=127.0.0.1
spring.redis.shiro.port=6379
spring.redis.shiro.timeout=5000
#没有密码写了会报错
#spring.redis.shiro.password=123456
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ShiroRedisConfig {
@Value("${spring.redis.shiro.host}")
private String host;
@Value("${spring.redis.shiro.port}")
private int port;
@Value("${spring.redis.shiro.timeout}")
private int timeout;
// @Value("${spring.redis.shiro.password}")
// private String password;
@Bean
public RedisManager redisManager() {
RedisManager redisManager = new RedisManager();
redisManager.setHost(host);
redisManager.setPort(port);
redisManager.setExpire(1800);// 配置缓存过期时间
redisManager.setTimeout(timeout);
// redisManager.setPassword(password);
return redisManager;
}
@Bean
public RedisCacheManager redisCacheManager() {
RedisCacheManager redisCacheManager = new RedisCacheManager();
redisCacheManager.setRedisManager(redisManager());
return redisCacheManager;
}
@Bean
public RedisSessionDAO redisSessionDAO() {
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
redisSessionDAO.setRedisManager(redisManager());
return redisSessionDAO;
}
}
4.Swagger配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@EnableSwagger2
@Configuration
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
/**
* Swagger会扫描该包下所有Controller定义的API,并产生文档内容(除了被@ApiIgnore注解的API)
*/
.apis(RequestHandlerSelectors.basePackage("com.example.shirospringboot.controller"))
/**
* 可以根据url路径设置哪些请求加入文档,忽略哪些请求
*/
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Shiro-Springboot Swagger2 APIs")
.description("shiro-springboot项目controller接口文档")
.version("1.0")
.build();
}
}
5.安全认证和权限验证的核心,自定义Realm
import com.example.shirospringboot.entity.User;
import com.example.shirospringboot.service.impl.UserServiceImpl;
import org.apache.shiro.SecurityUtils;
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.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.HashSet;
import java.util.Set;
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserServiceImpl userService;
/**
* 认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
/**
* 获取当前登录的主题
*/
String username = (String) token.getPrincipal();
User user = userService.getUserByUserName(username);
if(user==null){
throw new AuthenticationException();
}
String credentials = user.getPassword();
ByteSource credentialsSalt = ByteSource.Util.bytes(user.getSalt());
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
user.getUsername(), //用户名
credentials, //密码
credentialsSalt,
getName() //当前realm对象的name,调用父类的getName()方法即可
);
Session session = SecurityUtils.getSubject().getSession();
session.setAttribute("USER_SESSION", user);
return authenticationInfo;
/**
* String name="zhujie",password="123",salt= SaltUtil.getSalt();
* System.out.println("salt:"+salt);
* ByteSource saltByteSource = ByteSource.Util.bytes(salt);
* String newPs = new SimpleHash("MD5", password, salt, 1024).toHex();
* System.out.println("saltByteSource:"+saltByteSource);
* System.out.println("密码:"+newPs);
*/
}
/**
* 授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
Session session = SecurityUtils.getSubject().getSession();
System.out.println("授权方法获取用户:"+session.getAttribute("USER_SESSION"));
User user = (User) session.getAttribute("USER_SESSION");
Set<String> roleSet = new HashSet<>();
Set<String> permissionSet = new HashSet<>();
userService.getUserRoles(user.getUsername()).forEach(role -> roleSet.add(role.getName()));
userService.getUserPermissions(user.getUsername()).forEach(permission -> permissionSet.add(permission.getName()));
info.setRoles(roleSet);
info.setStringPermissions(permissionSet);
return info;
}
}
6.全局异常处理器
import com.example.shirospringboot.Result.Result;
import com.example.shirospringboot.Result.ResultUtil;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.ExpiredCredentialsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 如果身份验证失败请捕获 AuthenticationException 或其子类,常见的如:
* DisabledAccountException(禁用的帐号)、
* LockedAccountException(锁定的帐号)、
* UnknownAccountException(错误的帐号)、
* ExcessiveAttemptsException(登录失败次数过多)、
* IncorrectCredentialsException (错误的凭证)、
* ExpiredCredentialsException(过期的凭证)等
* 具体请查看其继承关系;
* 对于页面的错误消息展示,最好使用如 “用户名 / 密码错误” 而不是 “用户名错误”/“密码错误”,防止一些恶意用户非法扫描帐号库;
*/
//无权限
@ExceptionHandler(value = UnauthorizedException.class)
public Result handler(UnauthorizedException e) {
return ResultUtil.NO_PERMISSION();
}
//身份过期
@ExceptionHandler(value = ExpiredCredentialsException.class)
public Result handler(ExpiredCredentialsException e) {
return ResultUtil.IDENTITY_EXPIRED();
}
//没有登陆
@ExceptionHandler(value = UnauthenticatedException.class)
public Result handler(UnauthenticatedException e) {
return ResultUtil.NOT_LOGGED_IN();
}
//密码错误
@ExceptionHandler(value = IncorrectCredentialsException.class)
public Result handler(IncorrectCredentialsException e) {
return ResultUtil.INCORRECT_PASSWORD();
}
//用户不存在
@ExceptionHandler(value = AuthenticationException.class)
public Result handler(AuthenticationException e) {
return ResultUtil.USER_NOT_FOUND();
}
//账号冻结
@ExceptionHandler(value = LockedAccountException.class)
public Result handler(LockedAccountException e) {
return ResultUtil.ACCOUNT_FREEZING();
}
}
7.因为现在的项目大多都是前后端分离的,所以我们需要实现自己的session管理
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.Serializable;
public class MySessionManager extends DefaultWebSessionManager {
private static final String TOKEN = "token";
private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";
public MySessionManager() {
super();
}
@Override
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
String id = WebUtils.toHttp(request).getHeader(TOKEN);
//如果请求头中有 token 则其值为sessionId
if (!StringUtils.isEmpty(id)) {
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
return id;
} else {
//否则按默认规则从cookie取sessionId
return super.getSessionId(request, response);
}
}
}
8.控制器
import com.example.shirospringboot.Result.Result;
import com.example.shirospringboot.Result.ResultUtil;
import com.example.shirospringboot.entity.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
@Api(value="LoginController|登录控制器")
@RestController
@RequestMapping("/")
public class LoginController {
@ApiOperation(value = "用户登录接口", notes = "提供用户名和密码")
@PostMapping("/login")
public Result login(@ApiParam(name = "user",value = "登录用户",required = true) @RequestBody User user){
UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
Subject subject = SecurityUtils.getSubject();
HashMap<String, Object> map = new HashMap<>();
try {
subject.login(token);
map.put("token", subject.getSession().getId());
} catch (IncorrectCredentialsException e) {
//密码错误
throw e;
} catch (LockedAccountException e) {
//冻结
throw e;
} catch (AuthenticationException e) {
//用户不存在
throw e;
} catch (Exception e) {
return ResultUtil.EXCEPTION_UNKNOWN();
}
System.out.println(user.getUsername()+"已登录");
return ResultUtil.SUCCESS("登陆成功",null);
}
@ApiOperation("用户登出接口")
@GetMapping("/logout")
public Result logout(){
SecurityUtils.getSubject().logout();
return ResultUtil.SUCCESS("已退出登录",null);
}
@ApiOperation("用户权限测试接口")
@GetMapping("/test")
@RequiresRoles(value = {"admin"})
@RequiresPermissions(value = {"order:query:zhujie"})
public Result test(){
return ResultUtil.SUCCESS("test",null);
}
}
常用注解
@RequiresGuest 代表无需认证即可访问,同理的就是 /path=anon
@RequiresAuthentication 需要认证,只要登录成功后就允许你操作
@RequiresPermissions 需要特定的权限,没有则抛出 AuthorizationException
@RequiresRoles 需要特定的橘色,没有则抛出 AuthorizationException
9.以上就是shiro登陆和鉴权的主要配置和类,下面补充一下其他信息。
因为数据是模拟的,所以在登陆认证的时候,并没有通过数据库查用户信息,可以通过以下方式模拟加密后的密码:
String name="zhujie",password="123",salt= SaltUtil.getSalt();
System.out.println("salt:"+salt); //数据库salt字段
ByteSource saltByteSource = ByteSource.Util.bytes(salt);
String newPs = new SimpleHash("MD5", password, salt, 1024).toHex();
System.out.println("saltByteSource:"+saltByteSource);
System.out.println("密码:"+newPs); // 数据库password字段
}
UserService添加两个方法,便于调用。
public interface IUserService extends IService<User> {
User getUserByUserName(String username);
List<Role> getUserRoles(String username);
List<Permission> getUserPermissions(String username);
}
}
随机生成盐
import java.util.Random;
public class SaltUtil {
static char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*()_+".toCharArray();
static int length=32;
public static String getSalt(int saltLength){
StringBuilder sb = new StringBuilder();
for(int i = 0; i < saltLength; i++){
/**
* Random().nextInt()返回值为[0,n)
*/
char aChar = chars[new Random().nextInt(chars.length)];
sb.append(aChar);
}
return sb.toString();
}
public static String getSalt(){
return getSalt(length);
}
}
统一结果封装
import io.swagger.annotations.ApiModel;
import lombok.Data;
@Data
@ApiModel("统一封装返回对象")
public class Result<T> {
/** 错误码. */
private Integer code;
/** 提示信息. */
private String msg;
/** 具体的内容. */
private T data;
}
public enum ResultEnum {
SUCCESS(200, "操作成功"),
EXCEPTION_NOT_LOGGED_IN(401, "未登录,请登录"),
EXCEPTION_USER_NOT_FOUND(401,"用户不存在"),
EXCEPTION_INCORRECT_PASSWORD(401,"密码错误"),
EXCEPTION_IDENTITY_EXPIRED(401, "身份已过期,请重新登录"),
EXCEPTION_ACCOUNT_FREEZING(401, "账号已被冻结"),
EXCEPTION_NO_PERMISSION(402, "无权限操作"),
EXCEPTION_UNKNOWN(400, "未知异常");
private Integer code;
private String msg;
ResultEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
import org.apache.commons.lang3.StringUtils;
public class ResultUtil {
/**
* 成功
*/
public static Result SUCCESS(String message,Object object) {
Result result = new Result();
result.setCode(ResultEnum.SUCCESS.getCode());
if(StringUtils.isBlank(message)){
result.setMsg(ResultEnum.SUCCESS.getMsg());
}else{
result.setMsg(message);
}
result.setData(object);
return result;
}
public static Result SUCCESS() {
return SUCCESS(null,null);
}
/**
* 未登录
*/
public static Result NOT_LOGGED_IN() {
Result result = new Result();
result.setCode(ResultEnum.EXCEPTION_NOT_LOGGED_IN.getCode());
result.setMsg(ResultEnum.EXCEPTION_NOT_LOGGED_IN.getMsg());
return result;
}
/**
* 用户不存在
*/
public static Result USER_NOT_FOUND() {
Result result = new Result();
result.setCode(ResultEnum.EXCEPTION_USER_NOT_FOUND.getCode());
result.setMsg(ResultEnum.EXCEPTION_USER_NOT_FOUND.getMsg());
return result;
}
/**
* 密码错误
*/
public static Result INCORRECT_PASSWORD() {
Result result = new Result();
result.setCode(ResultEnum.EXCEPTION_INCORRECT_PASSWORD.getCode());
result.setMsg(ResultEnum.EXCEPTION_INCORRECT_PASSWORD.getMsg());
return result;
}
/**
* 身份失效
*/
public static Result IDENTITY_EXPIRED() {
Result result = new Result();
result.setCode(ResultEnum.EXCEPTION_IDENTITY_EXPIRED.getCode());
result.setMsg(ResultEnum.EXCEPTION_IDENTITY_EXPIRED.getMsg());
return result;
}
/**
* 无权限
*/
public static Result NO_PERMISSION() {
Result result = new Result();
result.setCode(ResultEnum.EXCEPTION_NO_PERMISSION.getCode());
result.setMsg(ResultEnum.EXCEPTION_NO_PERMISSION.getMsg());
return result;
}
/**
* 无权限
*/
public static Result ACCOUNT_FREEZING() {
Result result = new Result();
result.setCode(ResultEnum.EXCEPTION_ACCOUNT_FREEZING.getCode());
result.setMsg(ResultEnum.EXCEPTION_ACCOUNT_FREEZING.getMsg());
return result;
}
/**
* 未知异常
*/
public static Result EXCEPTION_UNKNOWN() {
Result result = new Result();
result.setCode(ResultEnum.EXCEPTION_UNKNOWN.getCode());
result.setMsg(ResultEnum.EXCEPTION_UNKNOWN.getMsg());
return result;
}
}
10.出现的问题
问题1
<!-- 引入devtools之后,项目会用一个base类加载器来加载不改变的类,而会用restart类加载器来加载改变的类。当项目产生修改时,base类加载器不变化,而restart类会重建。类修改时,只对修改过的类重新加载,使得项目重新启动时速度极快。-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-devtools</artifactId>-->
<!-- <scope>runtime</scope>-->
<!-- <optional>true</optional>-->
<!-- </dependency>-->
<!-- springboot-test-->
添加以上依赖后,从缓存中读取用户信息会出现cast异常,所以不添加该热部署依赖即可
User user = (User) session.getAttribute("USER_SESSION");
问题2
放行Swagger2页面
filterChainDefinitionMap.put("/swagger-ui.html","anon");
filterChainDefinitionMap.put("/swagger/**","anon");
filterChainDefinitionMap.put("/webjars/**", "anon");
filterChainDefinitionMap.put("/swagger-resources/**","anon");
filterChainDefinitionMap.put("/v2/**","anon");
filterChainDefinitionMap.put("/static/**", "anon");
最后
以上就是尊敬蚂蚁为你收集整理的shiro(session+redis),基于springboot,基于前后端分离,从登录认证到鉴权1.导入shiro依赖2.shiro配置类3.ShiroRedis配置类4.Swagger配置类5.安全认证和权限验证的核心,自定义Realm6.全局异常处理器7.因为现在的项目大多都是前后端分离的,所以我们需要实现自己的session管理8.控制器9.以上就是shiro登陆和鉴权的主要配置和类,下面补充一下其他信息。10.出现的问题的全部内容,希望文章能够帮你解决shiro(session+redis),基于springboot,基于前后端分离,从登录认证到鉴权1.导入shiro依赖2.shiro配置类3.ShiroRedis配置类4.Swagger配置类5.安全认证和权限验证的核心,自定义Realm6.全局异常处理器7.因为现在的项目大多都是前后端分离的,所以我们需要实现自己的session管理8.控制器9.以上就是shiro登陆和鉴权的主要配置和类,下面补充一下其他信息。10.出现的问题所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复