前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >springboot集成shiro

springboot集成shiro

作者头像
小尘哥
发布2018-08-15 10:36:14
1.5K0
发布2018-08-15 10:36:14
举报
文章被收录于专栏:小尘哥的专栏小尘哥的专栏

是不是发现一般权限模块都是领导(或者技术大神)写的,你只管用就好了?不想当领导的程序猿不是好厨子。废话少说,先简单说下怎么用,黑猫白猫,会写权限才可能是高级猫,至于shiro是什么,请移步shiro官网

1、添加依赖

代码语言:javascript
复制
 <dependency>

 <groupId>org.apache.shiro</groupId>

 <artifactId>shiro-core</artifactId>

 <version>${shiro.version}</version>

 </dependency>


 <dependency>

 <groupId>org.apache.shiro</groupId>

 <artifactId>shiro-web</artifactId>

 <version>${shiro.version}</version>

 </dependency>


 <dependency>

 <groupId>org.apache.shiro</groupId>

 <artifactId>shiro-spring</artifactId>

 <version>${shiro.version}</version>

 </dependency>


 <dependency>

 <groupId>net.mingsoft</groupId>

 <artifactId>shiro-freemarker-tags</artifactId>

 <version>${shiro-freemarker.version}</version>

 </dependency>

2、重写AuthorizingRealm

AuthorizingRealm主要包括两个方法:doGetAuthorizationInfo(PrincipalCollection principals)和doGetAuthenticationInfo(AuthenticationToken token) 1.doGetAuthenticationInfo(AuthenticationToken token)在登录认证时候被调用,即SecurityUtils.getSubject().login()执行时候被调用 2.doGetAuthorizationInfo(PrincipalCollection principals)获取权限认证信息,即SecurityUtils.getSubject().isPermitted()执行时候被调用 我这里定义成abstract 是为了提取该类为公用,其他项目可以复用集成。

代码语言:javascript
复制
public abstract class AbstarctAuthorizingRealm extends AuthorizingRealm {


 @Resource

 private IUserService userService;


 @Override

 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

 Object primaryPrincipal = principals.getPrimaryPrincipal();

 if (primaryPrincipal == null) {

 return null;

 }


 IUser user = (IUser) primaryPrincipal;


 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

 info.setStringPermissions(findPermissions(user));

 info.setRoles(findRoles(user));


 return info;

 }



 /**

 * 获取用户的权限集合

 */

 protected abstract Set<String> findPermissions(IUser user);

 /**

 * 获取用户的角色集合

 */

 protected abstract Set<String> findRoles(IUser user);


 @Override

 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

 UsernamePasswordToken upt = (UsernamePasswordToken) token;

 String username = upt.getUsername();

 char[] password = upt.getPassword();

 if (StringUtils.isBlank(username)) {

 throw new MustUsernameException();

 }


 if (password == null || password.length == 0) {

 throw new MustPasswordException();

 }


 IUser user = userService.findUserByUsername(username);

 if (user == null) {

 throw new UnknownAccountException();

 }


 if (Boolean.TRUE.equals(user.getLocked())) {

 throw new LockedAccountException();

 }


 if (Boolean.TRUE.equals(user.getDisabled())) {

 throw new DisabledAccountException();

 }


 AuthenticationInfo authenticationInfo = assertAuthenticationInfo(user);


 return authenticationInfo;

 }


 protected AuthenticationInfo assertAuthenticationInfo(IUser user) {

 SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), getName());

 return authenticationInfo;

 }


 protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info)

 throws AuthenticationException {

 CredentialsMatcher cm = getCredentialsMatcher();

 if (cm != null) {

 if (!cm.doCredentialsMatch(token, info)) {

 throw new IncorrectCredentialsException();

 }

 } else {

 throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify "

 + "credentials during authentication. If you do not wish for credentials to be examined, you "

 + "can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance.");

 }

 }


 public IUserService getUserService() {

 return userService;

 }


 public void setUserService(IUserService userService) {

 this.userService = userService;

 }

IUser也是一个接口,包括用户基本登录信息,方便每个用到的项目自己做实现

代码语言:javascript
复制
public interface IUser {


 String getUsername();


 String getPassword();


 Boolean getDisabled();


 Integer getDeleted();


 Boolean getLocked();


}

3、登录成功回调(重写FormAuthenticationFilter)

比如登录成功后需要修改用户最后登录时间,登录ip,记录日志等等操作都可以在这里进行。

代码语言:javascript
复制
public class KaptchaFormAuthenticationFilter extends FormAuthenticationFilter {


 final Logger logger = LoggerFactory.getLogger(getClass());


 private MessageSourceAccessor messageSourceAccessor;


 public KaptchaFormAuthenticationFilter(MessageSourceAccessor messageSourceAccessor) {

 this.messageSourceAccessor = messageSourceAccessor;

 }


 protected boolean onAccessDenied(ServletRequest request, ServletResponse response, Object mappedValue)

 throws Exception {

 if (request.getAttribute(getFailureKeyAttribute()) != null) {

 return true;

 }

 return super.onAccessDenied(request, response, mappedValue);

 }


 @Override

 protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request,

 ServletResponse response) throws Exception {

 HttpServletRequest httpServletRequest = (HttpServletRequest) request;

 HttpServletResponse httpServletResponse = (HttpServletResponse) response;

 if ("XMLHttpRequest".equalsIgnoreCase(httpServletRequest.getHeader("X-Requested-With"))) {

 httpServletResponse.setCharacterEncoding("UTF-8");

 PrintWriter out = null;

 try{

 out = httpServletResponse.getWriter();

 out.println(FastJsonUtils.toJSONString(ResultModel.defaultSuccess(null)));

 out.flush();

 }finally{

 if(out != null){

 out.close();

 }

 }

 return false;

 }


 return super.onLoginSuccess(token, subject, request, response);


 }


 @Override

 protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request,

 ServletResponse response) {

 HttpServletRequest httpServletRequest = (HttpServletRequest) request;

 HttpServletResponse httpServletResponse = (HttpServletResponse) response;

 if ("XMLHttpRequest".equalsIgnoreCase(httpServletRequest.getHeader("X-Requested-With"))) {

 String className = e.getClass().getName();

 ResultModel rm = new ResultModel(ResultStatus.FAIL.getCode(), messageSourceAccessor.getMessage(className));

 PrintWriter out = null;

 try {

 out = httpServletResponse.getWriter();

 out.println(FastJsonUtils.toJSONString(rm));

 out.flush();

 } catch (IOException e1) {

 if(logger.isInfoEnabled()){

 e1.printStackTrace();

 }

 }finally{

 if(out != null){

 out.close();

 }

 }

 return false;

 }

 return super.onLoginFailure(token, e, request, response);

 }


 public MessageSourceAccessor getMessageSourceAccessor() {

 return messageSourceAccessor;

 }


 public void setMessageSourceAccessor(MessageSourceAccessor messageSourceAccessor) {

 this.messageSourceAccessor = messageSourceAccessor;

 }

4、springboot配置shiroConfig

代码语言:javascript
复制
package com.mos.easyboot.admin.config;


import com.google.common.collect.Maps;

import com.mos.easyboot.admin.config.service.impl.PermissionService;

import com.mos.easyboot.admin.config.service.impl.UserService;

import com.mos.easyboot.tools.shiro.KaptchaValidateFilter;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;

import org.apache.shiro.spring.LifecycleBeanPostProcessor;

import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;

import org.apache.shiro.spring.web.ShiroFilterFactoryBean;

import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;

import org.apache.shiro.web.filter.authc.LogoutFilter;

import org.apache.shiro.web.mgt.DefaultWebSecurityManager;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.beans.factory.config.MethodInvokingFactoryBean;

import org.springframework.context.MessageSource;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.DependsOn;

import org.springframework.context.support.MessageSourceAccessor;


import javax.servlet.Filter;

import java.util.Map;


/**

 * @author 小尘哥

 */

@Configuration

public class ShiroConfig{



 @Bean(name = "securityManager")

 public DefaultWebSecurityManager securityManager(PermissionService permissionService) {

 DefaultWebSecurityManager manager = new DefaultWebSecurityManager();

 manager.setRealm(userRealm(permissionService));

 return manager;

 }


 @Bean

 public MethodInvokingFactoryBean setSecurityManager(PermissionService permissionService) {

 MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();

 methodInvokingFactoryBean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");

 methodInvokingFactoryBean.setArguments(securityManager(permissionService));

 return methodInvokingFactoryBean;

 }


 @Bean

 @DependsOn(value = "lifecycleBeanPostProcessor")

 public UserRealm userRealm(PermissionService permissionService) {

 UserRealm userRealm = new UserRealm(permissionService);

 userRealm.setCredentialsMatcher(credentialsMatcher());

 return userRealm;

 }


 @Bean

 public HashedCredentialsMatcher credentialsMatcher() {

 HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();

 credentialsMatcher.setHashAlgorithmName("MD5");

// credentialsMatcher.setHashIterations(2); MD5加密迭代次数1:MD5(str),2:MD5(MD5(str))

 return credentialsMatcher;

 }


 @Bean

 public FormAuthenticationFilter authcFilter(@Qualifier("messageSourceAccessor") MessageSourceAccessor messageSourceAccessor,

 @Qualifier("userService") UserService userService) {

 CustomFormAuthenticationFilter authenticationFilter = new CustomFormAuthenticationFilter(messageSourceAccessor,userService);

 authenticationFilter.setLoginUrl("/login");

 return authenticationFilter;

 }


 @Bean

 public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(

 @Qualifier("permissionService") PermissionService permissionService) {

 AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();

 authorizationAttributeSourceAdvisor.setSecurityManager(securityManager(permissionService));

 return authorizationAttributeSourceAdvisor;

 }


 public LogoutFilter logoutFilter() {

 LogoutFilter logout = new LogoutFilter();

 logout.setRedirectUrl("/login");

 return logout;

 }

 @Bean

 public KaptchaValidateFilter kaptchaValidate() {

 return new KaptchaValidateFilter();

 }


 @Bean(name = "shiroFilter")

 public ShiroFilterFactoryBean shiroFilter(@Qualifier("messageSourceAccessor") MessageSourceAccessor messageSourceAccessor,

 @Qualifier("userService") UserService userService,

 @Qualifier("permissionService") PermissionService permissionService) {

 ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();

 bean.setSecurityManager(securityManager(permissionService));

 bean.setLoginUrl("/toLogin");

 bean.setUnauthorizedUrl("/unauthor");

 bean.setSuccessUrl("/index");


 Map<String, Filter> filters = Maps.newHashMap();

 filters.put("kaptchaValidate", kaptchaValidate());

 filters.put("authc", authcFilter(messageSourceAccessor,userService));

 filters.put("logout", logoutFilter());

 bean.setFilters(filters);


 Map<String, String> filterChainDefinitionMap = Maps.newHashMap();

 filterChainDefinitionMap.put("/toLogin", "anon");

 filterChainDefinitionMap.put("/login*", "kaptchaValidate,authc");

 filterChainDefinitionMap.put("/logout", "logout");

 filterChainDefinitionMap.put("/demo/**", "anon");

 filterChainDefinitionMap.put("/kaptcha.jpg", "anon");

 filterChainDefinitionMap.put("/app/**", "anon");

 filterChainDefinitionMap.put("/images/**", "anon");

 filterChainDefinitionMap.put("/css/**", "anon");

 filterChainDefinitionMap.put("/js/**", "anon");

 filterChainDefinitionMap.put("/plugins/**", "anon");

 filterChainDefinitionMap.put("/**", "user");


 bean.setFilterChainDefinitionMap(filterChainDefinitionMap);


 return bean;

 }


 @Bean

 public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {

 return new LifecycleBeanPostProcessor();

 }


 @Bean

 public MessageSourceAccessor messageSourceAccessor(@Qualifier("messageSource") MessageSource messageSource){

 return new MessageSourceAccessor(messageSource);

 }

}

5、添加shiro拦截

代码语言:javascript
复制
@Bean

 public FilterRegistrationBean shiroFilterRegistration() {

 FilterRegistrationBean filterRegistration = new FilterRegistrationBean();

 filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter"));

 filterRegistration.setEnabled(true);

 filterRegistration.addUrlPatterns("/*");

 filterRegistration.setDispatcherTypes(DispatcherType.REQUEST);

 return filterRegistration;

 }

6、使用

controller直接加@RequiresPermissions("对应的权限")或@RequiresRoles("对应的角色")即可 模板上:<@shiro.hasPermission name="你定义的权限标识">

7、其他

有些代码没有贴出来,随后我会把整个项目开源出来,easy-boot,基于springboot的快速开发框架搭建方案,希望大家多多支(tu)持(cao)····

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-04-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 陌与尘埃 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、添加依赖
  • 2、重写AuthorizingRealm
  • 3、登录成功回调(重写FormAuthenticationFilter)
  • 4、springboot配置shiroConfig
  • 5、添加shiro拦截
  • 6、使用
  • 7、其他
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档