失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 前后端分离 springboot shiro+jwt token认证 权限校验

前后端分离 springboot shiro+jwt token认证 权限校验

时间:2021-08-21 17:51:29

相关推荐

前后端分离 springboot shiro+jwt token认证 权限校验

项目源码

国涛/springboot-shiro-jwt/dugt/springboot-shiro-jwt

GitHub - dugt-1998/springboot-shiro-jwt: 杜国涛的仓库杜国涛的仓库. Contribute to dugt-1998/springboot-shiro-jwt development by creating an account on GitHub./dugt-1998/springboot-shiro-jwt

核心部分

授权 认证

首先定义我们的配置类

/*** <p>* shiro核心配置类* </p>** @author duguotao* @version 1.0.0* @since Created in /11/11*/@Configurationpublic class ShiroConfig {/*** 先经过token过滤器,如果检测到请求头存在 token,则用 token 去 login,接着走 Realm 去验证*/@Beanpublic ShiroFilterFactoryBean factory(SecurityManager securityManager) {ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();Map<String, Filter> filterMap = new LinkedHashMap<>();//设置我们自定义的JWT过滤器filterMap.put("jwt", new JWTFilter());factoryBean.setFilters(filterMap);factoryBean.setSecurityManager(securityManager);factoryBean.setUnauthorizedUrl("/unauthorized/无权限");Map<String, String> filterRuleMap = new HashMap<>();// 所有请求通过我们自己的JWT FilterfilterRuleMap.put("/**", "jwt");//内置过滤器,可以实现权限相关的拦截器// user:如果使用remember的功能才能直接访问// perms:必须得到资源权限才可访问// role:必须得到角色权限才可访问// 放行不需要权限认证的接口// swagger 静态资源 或websocket服务器链接接口 都可在此配置filterRuleMap.put("/login", "anon");filterRuleMap.put("/unauthorized/**", "anon");factoryBean.setFilterChainDefinitionMap(filterRuleMap);return factoryBean;}/*** 注入 securityManager*/@Beanpublic SecurityManager securityManager(UserRealm customRealm) {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();// 设置自定义 realm.securityManager.setRealm(customRealm);/** 关闭shiro自带的session*/DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();defaultSessionStorageEvaluator.setSessionStorageEnabled(false);subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);securityManager.setSubjectDAO(subjectDAO);return securityManager;}/*** 添加注解支持*/@Beanpublic DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();// 强制使用cglib,防止重复代理和可能引起代理出错的问题defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);return defaultAdvisorAutoProxyCreator;}@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();advisor.setSecurityManager(securityManager);return advisor;}@Beanpublic LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {return new LifecycleBeanPostProcessor();}}

自定义relam

/*** <p>* 自定义Realm, 实现Shiro安全认证* </p>** @author duguotao* @version 1.0.0* @since Created in /11/11*/@Component@RequiredArgsConstructorpublic class UserRealm extends AuthorizingRealm {final UserService userService;/*** 必须重写此方法,不然会报错*/@Overridepublic boolean supports(AuthenticationToken token) {return token instanceof JWTToken;}/*** 认证*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {String token = (String) authenticationToken.getCredentials();// 解密获得username,用于和数据库进行对比String username = JWTUtil.getUsername(token);if (username == null || !JWTUtil.verify(token, username)) {throw new AuthenticationException("token认证失败或token已过期!");}userService.auth(username);return new SimpleAuthenticationInfo(token, token, "MyRealm");}/*** 授权*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {String username = JWTUtil.getUsername(principals.toString());SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();// 获得该用户角色String role = userService.getRole(username);// 用户拥有的权限List<String> permission = userService.getPermission(username);Set<String> roleSet = new HashSet<>();roleSet.add(role);Set<String> permissionSet = new HashSet<>(permission);//设置该用户拥有的角色和权限info.setRoles(roleSet);info.setStringPermissions(permissionSet);return info;}}

目前常用开发架构前后端分离,前后端分离项目就不能采用之前的cookie而是现在的token方式

jwt对token的认证还是不错的

首先定义jwt过滤器继承 BasicHttpAuthenticationFilter 通过header中的token信息作处理

/*** <p>* 自定义过滤器 对token相关操作* </p>** @author duguotao* @version 1.0.0* @since Created in /11/11*/public class JWTFilter extends BasicHttpAuthenticationFilter {private final Logger logger = LoggerFactory.getLogger(this.getClass());private static final String TOKEN = "token";/*** 校验token*/@Overrideprotected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws UnauthorizedException {if (!isLoginAttempt(request, response)) {return false;}try {executeLogin(request, response);return true;} catch (Exception e) {//token 错误responseError(response, e.getMessage());return false;}}/*** 判断用户是否想要登入。* 检测 header 里面是否包含 token 字段*/@Overrideprotected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {HttpServletRequest req = (HttpServletRequest) request;String token = req.getHeader(TOKEN);return token != null;}/*** 执行登陆操作*/@Overrideprotected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {HttpServletRequest httpServletRequest = (HttpServletRequest) request;String token = httpServletRequest.getHeader(TOKEN);JWTToken jwtToken = new JWTToken(token);// 提交给realm进行登入,如果错误它会抛出异常并被捕获getSubject(request, response).login(jwtToken);// 如果没有抛出异常则代表登入成功,返回truereturn true;}/*** 对跨域提供支持*/@Overrideprotected boolean preHandle(ServletRequest request, ServletResponse response) throws 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"));// 跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {httpServletResponse.setStatus(HttpStatus.OK.value());return false;}return super.preHandle(request, response);}/*** 将非法请求跳转到 /unauthorized/***/private void responseError(ServletResponse response, String message) {try {HttpServletResponse httpServletResponse = (HttpServletResponse) response;//设置编码,否则中文字符在重定向时会变为空字符串message = URLEncoder.encode(message, "UTF-8");httpServletResponse.sendRedirect("/unauthorized/" + message);} catch (IOException e) {logger.error(e.getMessage());}}}

测试代码

/*** <p>* 测试一下* </p>** @author duguotao* @version 1.0.0* @since Created in /11/11*/@RestController@RequiredArgsConstructorpublic class UserController {final UserService userService;final HttpServletRequest httpServletRequest;@GetMapping("/login")public JsonResult<String> login(String username, String password) {userService.login(username, password);return JsonResult.OK(JWTUtil.createToken(username));}// -------------- 权限注解 ----------------@GetMapping("/getM1")@RequiresPermissions(value = "perm:hello")public JsonResult<String> getM1() {return JsonResult.OK("hello word");}@GetMapping("/getM2")@RequiresPermissions(value = {"perm:hello", "perm:test"}, logical = Logical.OR)public JsonResult<String> getM2() {return JsonResult.OK("hello m2");}// -------------- 角色注解 ----------------@GetMapping("/getM3")@RequiresRoles(value = "admin")public JsonResult<String> getM3() {return JsonResult.OK("hello m3");}@GetMapping("/getM4")@RequiresRoles(value = {"admin", "emp"}, logical = Logical.OR)public JsonResult<String> getM4() {return JsonResult.OK("hello m4");}}

如果觉得《前后端分离 springboot shiro+jwt token认证 权限校验》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。