Shiro

参考视频
github
Docs

简介

image.png

入门

Shiro架构

安全框架 - 图2

认证

image.png
image.png

授权

image.png
image.png
image.png
image.pngimage.png

Realm

入门程序

  • maven

    1. <dependency>
    2. <groupId>org.apache.shiro</groupId>
    3. <artifactId>shiro-core</artifactId>
    4. <version>1.7.0</version>
    5. </dependency>
  • ShiroTest.java

    1. @Test
    2. public void test() {
    3. //创建安全管理器对象
    4. DefaultSecurityManager securityManager = new DefaultSecurityManager();
    5. //为安全管理器设置realm
    6. securityManager.setRealm(new IniRealm("classpath:shiro.ini"));
    7. //为SecurityUtils设置安全管理器
    8. SecurityUtils.setSecurityManager(securityManager);
    9. //获得subject主体
    10. Subject currentUser = SecurityUtils.getSubject();
    11. //创建令牌
    12. UsernamePasswordToken token = new UsernamePasswordToken("xiaochen", "123456");
    13. //用户使用令牌登入
    14. try {
    15. currentUser.login(token);
    16. System.out.println(currentUser.isAuthenticated() ? "认证成功" : "认证失败");
    17. } catch (UnknownAccountException uae) {
    18. System.out.println("用户不存在");
    19. } catch (IncorrectCredentialsException ice) {
    20. System.out.println("密码错误");
    21. } catch (LockedAccountException lae) {
    22. System.out.println("用户被锁定");
    23. }
    24. }
  • shiro.ini

    1. #用户信息
    2. [users]
    3. xiaochen = 123456
    4. zhangsan = 123456
    5. lisi = 123456

    自定义认证

  • CustomerRealm.java

    1. public class CustomerRealm extends AuthorizingRealm {
    2. //授权
    3. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    4. return null;
    5. }
    6. //认证
    7. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    8. String principal = String.valueOf(token.getPrincipal());
    9. //TODO 从数据库获得用户名
    10. if("xiaochen".equals(principal)){
    11. return new SimpleAuthenticationInfo(principal,token.getCredentials() , this.getName());
    12. }
    13. return null;
    14. }
    15. }
  • 设置Realm

    1. securityManager.setRealm(new CustomerRealm());

    自定义授权

  • CustomerRealm.java

    1. //授权
    2. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    3. System.out.println("该用户主身份: " + principals.getPrimaryPrincipal());
    4. //TODO 从数据库查询角色信息赋值给用户
    5. SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
    6. simpleAuthorizationInfo.addRole("user");
    7. simpleAuthorizationInfo.addStringPermission("user:*:01");
    8. simpleAuthorizationInfo.addStringPermission("product:create:*");
    9. return simpleAuthorizationInfo;
    10. }

    自定义加密

  • test.java ```java //创建安全管理器对象 DefaultSecurityManager securityManager = new DefaultSecurityManager(); //设置自定义realm CustomerRealm realm = new CustomerRealm(); //创建凭证匹配器 HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(); //设置算法 matcher.setHashAlgorithmName(“md5”); //散列次数 matcher.setHashIterations(1024); realm.setCredentialsMatcher(matcher);

securityManager.setRealm(realm);

  1. - CustomerRealm.java
  2. ```java
  3. //认证
  4. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
  5. String principal = String.valueOf(token.getPrincipal());
  6. if ("xiaochen".equals(principal)) {
  7. //用户名,,md5+salt后的密码,salt,realm名称
  8. return new SimpleAuthenticationInfo(principal, new Md5Hash("123456", "x0*7ps", 1024).toHex()
  9. , ByteSource.Util.bytes("x0*7ps")
  10. , this.getName());
  11. }
  12. return null;
  13. }

MD5

  1. //使用md5
  2. Md5Hash md5Hash = new Md5Hash("123");
  3. System.out.println(md5Hash.toHex());
  4. //使用md5 + salt
  5. Md5Hash md5Hash1 = new Md5Hash("123","x0*7ps");
  6. System.out.println(md5Hash1.toHex());
  7. //使用md5 + salt + hash散列
  8. Md5Hash md5Hash2 = new Md5Hash("123","x0*7ps",1024);
  9. System.out.println(md5Hash2.toHex());

异常

  1. Subject subject = SecurityUtils.getSubject();
  2. try {
  3. subject.login(new UsernamePasswordToken(userName,password));
  4. return "redirect:/index";
  5. }catch (UnknownAccountException e){
  6. model.addAttribute("message","用户不存在");
  7. }catch (IncorrectCredentialsException e) {
  8. model.addAttribute("message","密码错误");
  9. }

整合SpringBoot

  • maven

    1. <dependency>
    2. <groupId>org.apache.shiro</groupId>
    3. <artifactId>shiro-spring-boot-starter</artifactId>
    4. <version>1.7.0</version>
    5. </dependency>
  • ShiroConfig

    1. @Configuration
    2. public class ShiroConfig {
    3. //创建ShiroFilter 截拦所有请求
    4. @Bean
    5. public ShiroFilterFactoryBean shiroFilterFactoryBean(@Autowired DefaultWebSecurityManager defaultWebSecurityManager){
    6. ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    7. //为Filter配置安全管理器
    8. shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
    9. //配置截拦资源
    10. HashMap<String, String> map = new HashMap<String, String>();
    11. map.put("/user/login","anon"); //login设置为公共资源
    12. map.put("/user/register","anon");
    13. map.put("/register","anon");
    14. map.put("/user/getImage","anon");
    15. map.put("/**","authc"); //截拦所有资源
    16. shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
    17. //默认认证界面
    18. shiroFilterFactoryBean.setLoginUrl("/login");
    19. return shiroFilterFactoryBean;
    20. }
    21. //创建安全管理器
    22. @Bean
    23. public DefaultWebSecurityManager defaultWebSecurityManager(@Autowired Realm realm){
    24. DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
    25. defaultWebSecurityManager.setRealm(realm);
    26. return defaultWebSecurityManager;
    27. }
    28. @Bean
    29. public Realm realm(){
    30. CustomerRealm realm = new CustomerRealm();
    31. HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
    32. //设置算法
    33. matcher.setHashAlgorithmName("md5");
    34. //散列次数
    35. matcher.setHashIterations(1024);
    36. realm.setCredentialsMatcher(matcher);
    37. //开启缓存管理
    38. realm.setCacheManager(new EhCacheManager()); //设置缓存管理器
    39. realm.setCachingEnabled(true); //开启缓存
    40. realm.setAuthenticationCachingEnabled(true); //开启认证缓存
    41. realm.setAuthenticationCacheName("authenticationCache"); //缓存名
    42. realm.setAuthorizationCachingEnabled(true); //开启授权缓存
    43. realm.setAuthorizationCacheName("authorizationCache"); //缓存名
    44. return realm;
    45. }
    46. }
  • CustomerRealm

    1. public class CustomerRealm extends AuthorizingRealm {
    2. @Autowired
    3. private UserService userService;
    4. @Override
    5. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    6. //主身份(用户名)
    7. String principal = String.valueOf(principals.getPrimaryPrincipal());
    8. //根据主身份获取角色
    9. List<Role> roles = userService.findUserWithRole(principal).getRoles();
    10. if(!roles.isEmpty()){
    11. SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
    12. for(Role r : roles){
    13. simpleAuthorizationInfo.addRole(r.getRoleName());
    14. System.out.println(r.getRoleName());
    15. List<Perms> perms = userService.findPermsByRoleId(r.getId());
    16. if(!perms.isEmpty()){
    17. for(Perms p : perms){
    18. simpleAuthorizationInfo.addStringPermission(p.getPermsName());
    19. System.out.println(p.getPermsName());
    20. }
    21. }
    22. }
    23. //simpleAuthorizationInfo.addStringPermission("user:*:*");
    24. return simpleAuthorizationInfo;
    25. }
    26. return null;
    27. }
    28. @Override
    29. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    30. String username = String.valueOf(token.getPrincipal());
    31. QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
    32. queryWrapper.eq("user_name", username);
    33. User user = userService.getOne(queryWrapper);
    34. if (user != null) {
    35. return new SimpleAuthenticationInfo(username, user.getPassword(), ByteSource.Util.bytes(user.getSalt()), this.getName());
    36. }
    37. return null;
    38. }
    39. }

    常见过滤器

    | 配置缩写 | 对应的过滤器 | 功能 | | —- | —- | —- | | anon | AnonymousFilter | 指定url可以匿名访问 | | authc | FormAuthenticationFilter | 指定url需要form表单登录,默认会从请求中获取usernamepassword,rememberMe等参数并尝试登录,如果登录不了就会跳转到loginUrl配置的路径。我们也可以用这个过滤器做默认的登录逻辑,但是一般都是我们自己在控制器写登录逻辑的,自己写的话出错返回的信息都可以定制嘛。 | | authcBasic | BasicHttpAuthenticationFilter | 指定url需要basic登录 | | logout | LogoutFilter | 登出过滤器,配置指定url就可以实现退出功能,非常方便 | | noSessionCreation | NoSessionCreationFilter | 禁止创建会话 | | perms | PermissionsAuthorizationFilter | 需要指定权限才能访问 | | port | PortFilter | 需要指定端口才能访问 | | rest | HttpMethodPermissionFilter | 将http请求方法转化成相应的动词来构造一个权限字符串,这个感觉意义不大,有兴趣自己看源码的注释 | | roles | RolesAuthorizationFilter | 需要指定角色才能访问 | | ssl | SslFilter | 需要https请求才能访问 | | user | UserFilter | 需要已登录或“记住我”的用户才能访问 |

页面授权

使用jsp

  • 引入标签库

    1. <%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

    验证认证情况
  • user

    • 用户通过认证或通过记住我登录
  • guest
    • 用户没有身份认证
  • authenticated
    • 用户通过身份认证
    • image.png
    • image.png

验证权限和角色
  • hasRole
    • 含有角色XX
    • image.png
  • hasAnyRoles
    • 至少含有其中一个角色
    • image.png
  • hasPermission
    • 对某个操作具有权限
    • image.png
  • lacksPermission
    • 用户没有相应权限
  • lacksRole

    • 用户没有相应角色
      获得用户信息
  • principal

    • 用户名
    • image.png

      使用thymeleaf

  • maven

    1. <dependency>
    2. <groupId>com.github.theborakompanioni</groupId>
    3. <artifactId>thymeleaf-extras-shiro</artifactId>
    4. <version>2.0.0</version>
    5. </dependency>
  • xmlns

    1. xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"
  • shirpconfig加入shiro方言配置

    1. @Bean
    2. public ShiroDialect shiroDialect(){
    3. return new ShiroDialect();
    4. }
  • 使用 ```html

    Please login

Welcome back John! Not John? Click here to login.

Hello, , how are you today?

Update your contact information

Hello, , how are you today?

Please login in order to update your credit card information.

Administer the system

Sorry, you are not allowed to developer the system.

You are a developer and a admin.

You are a admin, vip, or developer.

添加用户

Sorry, you are not allowed to delete user accounts.

You can see or add users.

You can see or delete users.

Create a new User

  1. <a name="badff791"></a>
  2. ### 方法授权
  3. <a name="a4V5d"></a>
  4. #### 代码授权
  5. ![image.png](https://cdn.nlark.com/yuque/0/2020/png/1561124/1605611153107-0ade6e6b-25cc-4b7a-9729-87877a816595.png#align=left&display=inline&height=235&margin=%5Bobject%20Object%5D&name=image.png&originHeight=469&originWidth=732&size=284701&status=done&style=none&width=366)
  6. <a name="y9yhR"></a>
  7. #### [注解授权](https://wiki.jikexueyuan.com/project/shiro/jsp-label.html)
  8. - @RequiresRoles({"admin","user"})
  9. - 主体需要同时拥有角色admin和user
  10. - 否则抛出异常**AuthorizationException**
  11. - @RequiresPermissions("user:update:01")
  12. - 主体需要对应的操作权限
  13. - 否则抛出异常**AuthorizationException**
  14. <a name="abUzX"></a>
  15. ### CacheManager
  16. ![image.png](https://cdn.nlark.com/yuque/0/2020/png/1561124/1605659698024-614a2015-9126-4c7e-9ec1-c973996981b5.png#align=left&display=inline&height=304&margin=%5Bobject%20Object%5D&name=image.png&originHeight=607&originWidth=1514&size=189160&status=done&style=none&width=757)
  17. <a name="BRbmJ"></a>
  18. #### 结合echache
  19. - maven
  20. ```xml
  21. <dependency>
  22. <groupId>org.apache.shiro</groupId>
  23. <artifactId>shiro-ehcache</artifactId>
  24. <version>1.7.0</version>
  25. </dependency>

数据库设计

image-20200527204839080.png

shirotest.sql

实例

springboot_jsp_shiro.zip

加密算法

MD5

  • MD5算法不可逆
  • 相同的内容加密后结果一致

生成内容始终为16进制32为字符串