ShiroConfig 配置类:

    1. import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
    2. import com.ck.syscheck.shiro.ShiroRealm;
    3. import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
    4. import org.apache.shiro.cache.ehcache.EhCacheManager;
    5. import org.apache.shiro.codec.Base64;
    6. import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    7. import org.apache.shiro.web.mgt.CookieRememberMeManager;
    8. import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    9. import org.apache.shiro.web.servlet.SimpleCookie;
    10. import org.slf4j.Logger;
    11. import org.slf4j.LoggerFactory;
    12. import org.springframework.beans.factory.annotation.Qualifier;
    13. import org.springframework.context.annotation.Bean;
    14. import org.springframework.context.annotation.Configuration;
    15. import java.util.LinkedHashMap;
    16. import java.util.Map;
    17. @Configuration
    18. public class ShiroConfig {
    19. private Logger logger = LoggerFactory.getLogger(this.getClass());
    20. /**
    21. * 创建ShiroFilterFactoryBean
    22. *
    23. * @param securityManager
    24. * @return
    25. */
    26. @Bean
    27. public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
    28. ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    29. // 设置安全管理器
    30. shiroFilterFactoryBean.setSecurityManager(securityManager);
    31. //添加Shiro内置过滤器
    32. /**
    33. * 常用过滤器
    34. * anon:无需认证(登录)就可以访问
    35. * authc:必须认证才可以访问
    36. * user:如果使用RememberMe的功能,可以直接访问
    37. * perms:该资源必须得到资源权限才可以访问
    38. * role:该资源必须得到角色权限才可以访问
    39. */
    40. //登录的url
    41. shiroFilterFactoryBean.setLoginUrl("/api/loginPage");
    42. // 未授权url
    43. shiroFilterFactoryBean.setUnauthorizedUrl("/api/unAuth");
    44. // 登录成功后跳转的url
    45. shiroFilterFactoryBean.setSuccessUrl("/index");
    46. //注意此处要使用LinkenHashMap
    47. Map<String, String> filterMap = new LinkedHashMap<>();
    48. filterMap.put("/", "authc");
    49. // 定义filterChain,静态资源不拦截
    50. filterMap.put("/css/**", "anon");
    51. filterMap.put("/js/**", "anon");
    52. filterMap.put("/fonts/**", "anon");
    53. filterMap.put("/img/**", "anon");
    54. //放行某些个请求
    55. filterMap.put("/api/test", "anon");
    56. filterMap.put("/api/login", "anon");
    57. //授权过滤器,如果未授权会跳转到相应的页面
    58. filterMap.put("/api/add", "perms[api:add]");
    59. // 除上以外所有url都必须认证通过才可以访问,未通过认证自动访问LoginUrl
    60. // filterMap.put("/api/*", "authc");
    61. // filterMap.put("/home/*","authc");
    62. // filterMap.put("/config/*","authc");
    63. // 配置退出过滤器,其中具体的退出代码 Shiro已经替我们实现了
    64. filterMap.put("/logout", "logout");
    65. shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
    66. return shiroFilterFactoryBean;
    67. }
    68. /***
    69. * 创建DefaultWebSecurityManager
    70. * @param matcher
    71. * @return
    72. */
    73. @Bean
    74. public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("hashedCredentialsMatcher") HashedCredentialsMatcher matcher) {
    75. DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    76. //关联Realm
    77. securityManager.setRealm(shiroRealm(matcher));
    78. //记住我
    79. securityManager.setRememberMeManager(rememberMeManager());
    80. //缓存管理
    81. securityManager.setCacheManager(getEhCacheManager());
    82. return securityManager;
    83. }
    84. /**
    85. * 创建Relm
    86. *
    87. * @return
    88. */
    89. @Bean
    90. public ShiroRealm shiroRealm(HashedCredentialsMatcher matcher) {
    91. ShiroRealm myShiroRealm = new ShiroRealm();
    92. myShiroRealm.setCredentialsMatcher(matcher);
    93. return myShiroRealm;
    94. }
    95. /**
    96. * 配置ShiroDialect,用于整合shiro和Thymeleaf标签配合使用
    97. * @return
    98. */
    99. @Bean
    100. public ShiroDialect getShiroDialect(){
    101. return new ShiroDialect();
    102. }
    103. /**
    104. * 密码匹配凭证管理器
    105. *
    106. * @return
    107. */
    108. @Bean(name = "hashedCredentialsMatcher")
    109. public HashedCredentialsMatcher hashedCredentialsMatcher() {
    110. HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
    111. // 采用MD5方式加密
    112. hashedCredentialsMatcher.setHashAlgorithmName("MD5");
    113. // 设置加密次数
    114. hashedCredentialsMatcher.setHashIterations(1024);
    115. return hashedCredentialsMatcher;
    116. }
    117. /**
    118. * cookie对象
    119. * @return
    120. */
    121. public SimpleCookie rememberMeCookie() {
    122. // 设置cookie名称,对应login.html页面的<input type="checkbox" name="rememberMe"/>
    123. SimpleCookie cookie = new SimpleCookie("rememberMe");
    124. // 设置cookie的过期时间,单位为秒,这里为一天
    125. cookie.setMaxAge(86400);
    126. return cookie;
    127. }
    128. /**
    129. * cookie管理对象
    130. * @return
    131. */
    132. public CookieRememberMeManager rememberMeManager() {
    133. CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
    134. cookieRememberMeManager.setCookie(rememberMeCookie());
    135. // rememberMe cookie加密的密钥
    136. cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));
    137. return cookieRememberMeManager;
    138. }
    139. /**
    140. * 注入Ehcache缓存
    141. * @return
    142. */
    143. @Bean
    144. public EhCacheManager getEhCacheManager() {
    145. EhCacheManager ehCacheManager = new EhCacheManager();
    146. ehCacheManager.setCacheManagerConfigFile("classpath:config/ehcache-shiro.xml");
    147. return ehCacheManager;
    148. }
    149. }

    此类主要使用 hashedCredentialsMatcher 其加盐处理:

    1. /**
    2. * 密码匹配凭证管理器
    3. *
    4. * @return
    5. */
    6. @Bean(name = "hashedCredentialsMatcher")
    7. public HashedCredentialsMatcher hashedCredentialsMatcher() {
    8. HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
    9. // 采用MD5方式加密
    10. hashedCredentialsMatcher.setHashAlgorithmName("MD5");
    11. // 设置加密次数
    12. hashedCredentialsMatcher.setHashIterations(1024);
    13. return hashedCredentialsMatcher;
    14. }

    ShiroRealm 类:

    1. import com.ck.syscheck.model.*;
    2. import com.ck.syscheck.service.SysResourceService;
    3. import com.ck.syscheck.service.SysRoleResourceService;
    4. import com.ck.syscheck.service.SysUserRoleService;
    5. import com.ck.syscheck.service.SysUserService;
    6. import org.apache.commons.lang3.StringUtils;
    7. import org.apache.shiro.SecurityUtils;
    8. import org.apache.shiro.authc.*;
    9. import org.apache.shiro.authz.AuthorizationInfo;
    10. import org.apache.shiro.authz.SimpleAuthorizationInfo;
    11. import org.apache.shiro.realm.AuthorizingRealm;
    12. import org.apache.shiro.subject.PrincipalCollection;
    13. import org.apache.shiro.subject.Subject;
    14. import org.apache.shiro.util.ByteSource;
    15. import org.slf4j.Logger;
    16. import org.slf4j.LoggerFactory;
    17. import org.springframework.beans.factory.annotation.Autowired;
    18. import org.springframework.web.servlet.ModelAndView;
    19. import javax.annotation.Resource;
    20. import java.util.ArrayList;
    21. import java.util.List;
    22. public class ShiroRealm extends AuthorizingRealm {
    23. private Logger logger = LoggerFactory.getLogger(this.getClass());
    24. @Resource
    25. private SysUserService sysUserService;
    26. @Resource
    27. private SysUserRoleService sysUserRoleService;
    28. /**
    29. * 处理授权逻辑
    30. *
    31. * @param principalCollection
    32. * @return
    33. */
    34. @Override
    35. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    36. logger.info("执行授权逻辑+" + principalCollection.toString());
    37. //给资源进行授权
    38. SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
    39. Subject subject = SecurityUtils.getSubject();
    40. SysUser user = (SysUser) subject.getPrincipal();
    41. //获取用户角色ID
    42. SysUserRole byUserId = sysUserRoleService.findByUserId(user.getUid());
    43. //此处必须要和配置文件里的授权保持一致
    44. authorizationInfo.addStringPermission("api:add");
    45. return authorizationInfo;
    46. }
    47. /**
    48. * 处理认证逻辑
    49. *
    50. * @param authenticationToken
    51. * @return
    52. * @throws AuthenticationException
    53. */
    54. @Override
    55. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    56. UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
    57. // 获取用户输入的用户名和密码
    58. String userName = (String) token.getPrincipal();
    59. String password = new String((char[]) token.getCredentials());
    60. if (StringUtils.isNotBlank(userName)) {
    61. SysUser user = sysUserService.list(userName);
    62. //检测是否有此用户
    63. if (user == null) {
    64. // 没有找到账号异常
    65. throw new UnknownAccountException("用户名或密码错误!");
    66. }
    67. if (!token.getUsername().equals(user.getUsername())) {
    68. return null;
    69. }
    70. if (user.getStatus().equals("0")) {
    71. throw new LockedAccountException("账号已被锁定,请联系管理员!");
    72. }
    73. // 获取盐值,即用户名
    74. ByteSource salt = ByteSource.Util.bytes("AaBbCc");
    75. // 将账户名,密码,盐值,realmName实例化到SimpleAuthenticationInfo中交给Shiro来管理
    76. SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), salt, getName());
    77. //返回密码
    78. return simpleAuthenticationInfo;
    79. }
    80. return null;
    81. }
    82. }

    在Realm类中主要传递加盐的值:

    1. // 获取盐值,即用户名,此处盐值可以是活的,可以是用户输入的用户名等,也可以是写死的
    2. ByteSource salt = ByteSource.Util.bytes("AaBbCc");
    3. // 将账户名,密码,盐值,realmName实例化到SimpleAuthenticationInfo中交给Shiro来管理
    4. SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), salt, getName());
    5. //返回密码
    6. return simpleAuthenticationInfo;

    测试Shiro加盐,一般在注册的时候进行如下处理,最后保存到数据库。

    1. import org.apache.shiro.crypto.hash.SimpleHash;
    2. import org.apache.shiro.util.ByteSource;
    3. /**
    4. * 测试Shiro加盐,一般在注册的时候进行如下处理,最后保存到数据库
    5. * @author ck
    6. * @date 2019/7/8
    7. */
    8. public class Test {
    9. public static void main(String[] args) {
    10. String newPs = new SimpleHash("MD5", "123456", ByteSource.Util.bytes("AaBbCc"), 1024).toHex();
    11. System.out.println(newPs);
    12. //6a630026f54e3af745becaa18dd1ca6f
    13. }
    14. }