Shiro安全框架详解及示例

Shiro安全框架详解及示例,第1张

Shiro安全框架详解及示例

目录
      • 一、认识Shiro
          • 1、什么是Shiro?
          • 2、有哪些功能?
          • 3、Shiro架构(外部)
          • 4、Shiro架构(内部)
      • 二、授权方式
          • 5.1、三种授权方式
          • 5.2、授权流程
      • 三、认证方式
          • Realm:域
          • 自定义Realm
      • 四、Shiro InI配置(通常直接使用ShiroConfig)
          • 1、INI配置
          • 2、InI配置中的四大类
      • 五、Shiro编码加密
          • 1、散列算法
          • 2、加密/解密
            • 方式一
            • 方式二
          • 3、加密登录处理 HashedCredentialsMatcher方式
      • 六、Shiro 的默认Filter
          • 示例:
      • 七、shiro注解权限控制-5个权限注解
      • 八、示例Demo1(通过自定义token处理)
          • 1、用户的角色与权限
          • 2、编写ShiroConfig
          • 3、自定义Realm
          • 4、测试接口
          • 5、登录处理
      • 九、示例Demo2 (shiro直接处理用户名密码,并实现记住我、md5加密和缓存)
          • 1、用户的角色与权限
          • 2、编写ShiroConfig
          • 3、自定义Realm
          • 4、测试接口
          • 5、登录处理

一、认识Shiro 1、什么是Shiro?
  • Apache Shiro 是一个Java 的安全(权限)框架。
  • Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE环境,也可以用在JavaEE环
    境。
  • Shiro可以完成,认证,授权,加密,会话管理,Web集成,缓存等。
2、有哪些功能?

  • Authentication:身份认证、登录,验证用户是不是拥有相应的身份;
  • Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限,即判断用户能否
    进行什么 *** 作,如:验证某个用户是否拥有某个角色,或者细粒度的验证某个用户对某个资源是否
    具有某个权限!
  • Session Manager:会话管理,即用户登录后就是第一次会话,在没有退出之前,它的所有信息都
    在会话中;会话可以是普通的JavaSE环境,也可以是Web环境;
  • Cryptography:加密,保护数据的安全性,如密码加密存储到数据库中,而不是明文存储;
  • Web Support:Web支持,可以非常容易的集成到Web环境;
  • Caching:缓存,比如用户登录后,其用户信息,拥有的角色、权限不必每次去查,这样可以提高
    效率
  • Concurrency:Shiro支持多线程应用的并发验证,即,如在一个线程中开启另一个线程,能把权限
    自动的传播过去
  • Testing:提供测试支持;
  • Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;
  • Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了
3、Shiro架构(外部)

从外部来看shiro,即从应用程序角度来观察如何使用shiro完成工作:

  • Subject:代表当前"用户"。与当前应用程序交互的任何东西都是Subject,如爬虫、机器人。所有的Subject 都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager。Subject 是一个门面,SecurityManager 是实际的执行者。
  • SecurityManager:与安全有关的 *** 作都会与SecurityManager交互。它管理者所有Subject,是Shiro的核心,负责与其他组件进行交互。
  • Realm: Shiro从Realm中获取安全数据(用户、角色、权限)。SecurityManager需要从Realm中获取响应的用户信息进行比较用户身份是否合法,也需要从Realm中得到用户相应的角色/权限进行验证,以确定用户是否能够 *** 作。
4、Shiro架构(内部)

  • Subject:任何可以与应用交互的 用户;
  • Security Manager:相当于SpringMVC中的DispatcherServlet;是Shiro的心脏,所有具体的交互
    都通过Security Manager进行控制,它管理者所有的Subject,且负责进行认证,授权,会话,及
    缓存的管理。
  • Authenticator:负责Subject认证,是一个扩展点,可以自定义实现;可以使用认证策略
    (Authentication Strategy),即什么情况下算用户认证通过了;
  • Authorizer:授权器,即访问控制器,用来决定主体是否有权限进行相应的 *** 作;即控制着用户能
    访问应用中的那些功能;
  • Realm:可以有一个或者多个的realm,可以认为是安全实体数据源,即用于获取安全实体的,可
    以用JDBC实现,也可以是内存实现等等,由用户提供;所以一般在应用中都需要实现自己的realm
  • SessionManager:管理Session生命周期的组件,而Shiro并不仅仅可以用在Web环境,也可以用
    在普通的JavaSE环境中
  • CacheManager:缓存控制器,来管理如用户,角色,权限等缓存的;因为这些数据基本上很少改
    变,放到缓存中后可以提高访问的性能;
  • Cryptography:密码模块,Shiro 提供了一些常见的加密组件用于密码加密,解密等
二、授权方式 5.1、三种授权方式

5.2、授权流程

流程如下:

  • 1、首先调用 Subject.isPermitted*/hasRole*接口,其会委托给 SecurityManager,而 SecurityManager 接着会委托给 Authorizer;
  • 2、Authorizer 是真正的授权者,如果我们调用如 isPermitted(“user:view”),其首先会通过 PermissionResolver 把字符串转换成相应的 Permission 实例;
  • 3、在进行授权之前,其会调用相应的 Realm 获取 Subject 相应的角色/权限用于匹配传入的角色/权限;
  • 4、Authorizer 会判断 Realm 的角色/权限是否和传入的匹配,如果有多个 Realm,会委托给 ModularRealmAuthorizer 进行循环判断,如果匹配如 isPermitted*/hasRole* 会返回 true,否则返回 false 表示授权失败。

ModularRealmAuthorizer 进行多 Realm 匹配流程:

  • 首先检查相应的 Realm 是否实现了实现了 Authorizer;
  • 如果实现了 Authorizer,那么接着调用其相应的 isPermitted*/hasRole* 接口进行匹配;
  • 如果有一个 Realm 匹配那么将返回 true,否则返回 false。

如果 Realm 进行授权的话,应该继承 AuthorizingRealm,其流程是:

  • 如果调用 hasRole*,则直接获取 AuthorizationInfo.getRoles() 与传入的角色比较即可;首先如果调用如 isPermitted(“user:view”),首先通过 PermissionResolver 将权限字符串转换成相应的 Permission 实例,默认使用 WildcardPermissionResolver,即转换为通配符的 WildcardPermission;
  • 通过 AuthorizationInfo.getObjectPermissions() 得到 Permission 实例集合;通过 AuthorizationInfo.getStringPermissions() 得到字符串集合并通过 PermissionResolver 解析为 Permission 实例;然后获取用户的角色,并通过 RolePermissionResolver 解析角色对应的权限集合(默认没有实现,可以自己提供);
  • 接着调用 Permission.implies(Permission p) 逐个与传入的权限比较,如果有匹配的则返回 true,否则 false。
三、认证方式 Realm:域

Shiro 从 Realm获取安全数据(如用户、角色、权限),就是说 SecurityManager 要验证用户身份,那么它需要从 Realm 获取相应的用户进行比较以确定用户身份是否合法;也需要从 Realm 得到用户相应的角色 / 权限进行验证用户是否能进行 *** 作;可以把 Realm 看成 DataSource

String getName(); //返回一个唯一的Realm名字
boolean supports(AuthenticationToken token); //判断此Realm是否支持此Token
AuthenticationInfo getAuthenticationInfo(AuthenticationToken token)
 throws AuthenticationException;  //根据Token获取认证信息
自定义Realm
public class MyRealm implements Realm {
    @Override
    
    public String getName() {
        return "myrealm";
    }
    @Override
    public boolean supports(AuthenticationToken token) {
        //仅支持UsernamePasswordToken类型的Token
        return token instanceof UsernamePasswordToken; 
    }
    @Override
    public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String)token.getPrincipal();  //得到用户名
        String password = new String((char[])token.getCredentials()); //得到密码
        if(!"zhang".equals(username)) {
            throw new UnknownAccountException(); //如果用户名错误
        }
        if(!"123".equals(password)) {
            throw new IncorrectCredentialsException(); //如果密码错误
        }
        //如果身份认证验证成功,返回一个AuthenticationInfo实现;
        return new SimpleAuthenticationInfo(username, password, getName());
    }
}
四、Shiro InI配置(通常直接使用ShiroConfig) 1、INI配置

ini 配置文件类似于 Java 中的 properties(key=value),不过提供了将 key/value 分类的特性,key 是每个部分不重复即可,而不是整个配置文件。如下是 INI 配置分类:

[main]
#提供了对根对象securityManager及其依赖的配置
securityManager=org.apache.shiro.mgt.DefaultSecurityManager
…………
securityManager.realms=$jdbcRealm
[users]
#提供了对用户/密码及其角色的配置,用户名=密码,角色1,角色2
username=password,role1,role2
[roles]
#提供了角色及权限之间关系的配置,角色=权限1,权限2
role1=permission1,permission2
[urls]
#用于web,提供了对web url拦截相关的配置,url=拦截器[参数],拦截器
/index.html = anon
/admin
@Configuration
public class ShiroConfig {

    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);
        // 登录配置
        shiroFilter.setLoginUrl("/login");
        shiroFilter.setSuccessUrl("/");
        shiroFilter.setUnauthorizedUrl("/error/403");
        // 自定义过滤器
        Map filtersMap = new linkedHashMap<>();
        filtersMap.put("mlfc", new MyLoginFilter());
        shiroFilter.setFilters(filtersMap);
        // 拦截配置
        Map filterChainDefinitions = new linkedHashMap<>();
        filterChainDefinitions.put("/assets
    @PostMapping("/login")
    @ResponseBody
    public R login(HttpServletRequest request, String username, String password, String code, boolean rememberMe) {
        if (StringUtil.isBlank(username, password)) {
            return R.failed("账号或密码不能为空");
        }
        String sessionCode = (String) request.getSession().getAttribute("captcha");
        if (code == null || !sessionCode.equals(code.trim().toLowerCase())) {
            return R.failed("验证码不正确");
        }
        try {
            UsernamePasswordToken token = new UsernamePasswordToken(username, password, rememberMe);
            SecurityUtils.getSubject().login(token);
            return R.succeed("登录成功");
        } catch (UnknownAccountException e) {
            return R.failed("用户不存在");
        } catch (IncorrectCredentialsException e) {
            return R.failed("密码错误");
        } catch (ExcessiveAttemptsException eae) {
            return R.failed(" *** 作频繁,请稍后再试");
        }
    }
  • shiro默认登录过期时间是30分钟
//永不过期,在登陆最开始加上
SecurityUtils.getSubject().getSession().setTimeout(-1000L);
//其他时间 单位毫秒
SecurityUtils.getSubject().getSession().setTimeout(1800000);
六、Shiro 的默认Filter Filter名称说明anon无参,匿名访问,无需认证就可访问无参,匿名访问,无需认证就可访问authcorg.apache.shiro.web.filter.authc.FormAuthenticationFilter无参,表示需要认证才能访问authcBasic org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter无参,表示需要httpBasic认证才能访问logoutorg.apache.shiro.web.filter.authc.LogoutFilter退出拦截器,即退出后重定向的地址noSessionCreationorg.apache.shiro.web.filter.session.NoSessionCreationFilter不创建会话拦截器,调用 subject.getSession(false) 不会有什么问题,但是如果 subject.getSession(true) 将抛出 DisabledSessionException 异常;permsorg.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter权限授权拦截器,验证用户是否拥有所有权限portorg.apache.shiro.web.filter.authz.PortFilter端口拦截器,端口号不是指定端口号,则跳转过去restorg.apache.shiro.web.filter.authz.HttpMethodPermissionFilterrest风格拦截器,根据请求方式来识别rolesorg.apache.shiro.web.filter.authz.RolesAuthorizationFilter拥有某个角色权限才能访问sslorg.apache.shiro.web.filter.authz.SslFilter无参,SSL拦截器,只有请求协议是https才能通过userorg.apache.shiro.web.filter.authc.UserFilter无参,用户已经身份验证,或记住我登录可以访问 示例:
  1. /admin @Configuration public class ShiroConfig { //SecurityManager 是 Shiro 架构的核心,通过它来链接Realm和用户(文档中称之为Subject.) @Bean("securityManager") public SecurityManager securityManager(AuthRealm authRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(authRealm); //将Realm注入到SecurityManager中。 return securityManager; } @Bean("shiroFilter") public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean(); shiroFilter.setSecurityManager(securityManager); //auth过滤 Map filters = new HashMap<>(); filters.put("auth", new AuthFilter()); shiroFilter.setFilters(filters); Map filterMap = new linkedHashMap<>(); //authc表示需要验证身份才能访问,还有一些比如anon表示不需要验证身份就能访问等。 // anno匿名访问 auth验证 filterMap.put("/webjars @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; } //负责管理shiro的生命周期,项目中不加lifecyclebeanpostprocessor也没问题 @Bean("lifecycleBeanPostProcessor") public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } } 3、自定义Realm
    @Component
    public class AuthRealm extends AuthorizingRealm {
    
        @Autowired
        private ShiroService shiroService;
    
        private String salt = "lyp";
    
        @Override
        
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            //1. 从 PrincipalCollection 中来获取登录用户的信息
            User user = (User) principals.getPrimaryPrincipal();
            //Integer userId = user.getUserId();
            //2.添加角色和权限
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            for (Role role : user.getRoles()) {
                //2.1添加角色
                simpleAuthorizationInfo.addRole(role.getRoleName());
                for (Permission permission : role.getPermissions()) {
                    //2.1.1添加权限
                    simpleAuthorizationInfo.addStringPermission(permission.getPermission());
                }
            }
            return simpleAuthorizationInfo;
        }
    
        @Override
        
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            //获取token,既前端传入的token
            String accessToken = (String) token.getPrincipal();
            //1. 根据accessToken,查询用户信息
            SysToken tokenEntity = shiroService.findByToken(accessToken);
            //2. token失效
            if (tokenEntity == null || tokenEntity.getExpireTime().isBefore(LocalDateTime.now())) {
                throw new IncorrectCredentialsException("token失效,请重新登录");
            }
            //3. 调用数据库的方法, 从数据库中查询 username 对应的用户记录
            User user = shiroService.findByUserId(tokenEntity.getUserId());
            //4. 若用户不存在, 则可以抛出 UnknownAccountException 异常
            if (user == null) {
                throw new UnknownAccountException("用户不存在!");
            }
    
            //5. 根据用户的情况, 来构建 AuthenticationInfo 对象并返回. 通常使用的实现类为: SimpleAuthenticationInfo
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(
                    user, //用户
                    accessToken,
                    this.getName());  //Realm name
            return info;
        }
    }
    
    4、测试接口
    @Api(tags = "测试")
    @RestController
    public class TestController {
    
        @RequiresPermissions({"save"})
        @PostMapping("/save")
        public Map save(@RequestHeader("token")String token) {
            System.out.println("save");
            Map map = new HashMap();
            map.put("status", 200);
            map.put("msg", "当前用户有save的权力");
            return map;
        }
    
        @RequiresPermissions({"delete"})
        @DeleteMapping("/delete")
        public Map delete(@RequestHeader("token")String token) {
            System.out.println("delete");
            Map map = new HashMap();
            map.put("status", 200);
            map.put("msg", "当前用户有delete的权力");
            return map;
        }
    
        @RequiresPermissions({"update"})
        @PutMapping("update")
        public Map update(@RequestHeader("token")String token) {
            System.out.println("update");
            Map map = new HashMap();
            map.put("status", 200);
            map.put("msg", "当前用户有update的权力");
            return map;
        }
    
        @RequiresPermissions({"select"})
        @GetMapping("select")
        public Map select(@RequestHeader("token")String token) {
            System.out.println("select");
            Map map = new HashMap();
            map.put("status", 200);
            map.put("msg", "当前用户有select的权力");
            return map;
        }
    
        @RequiresRoles({"vip"})
        @GetMapping("/vip")
        public Map vip(@RequestHeader("token")String token) {
            System.out.println("vip");
            Map map = new HashMap();
            map.put("status", 200);
            map.put("msg", "当前用户有VIP角色");
            return map;
        }
        @RequiresRoles({"svip"})
        @GetMapping("/svip")
        public Map svip(@RequestHeader("token")String token) {
            System.out.println("svip");
            Map map = new HashMap();
            map.put("status", 200);
            map.put("msg", "当前用户有SVIP角色");
            return map;
        }
        @RequiresRoles({"p"})
        @GetMapping("/p")
        public Map p(@RequestHeader("token")String token) {
            System.out.println("p");
            Map map = new HashMap();
            map.put("status", 200);
            map.put("msg", "当前用户有P角色");
            return map;
        }
    }
    
    5、登录处理
    @Api(tags = "Shiro权限管理")
    @RestController
    public class ShiroController {
    
        private final ShiroService shiroService;
    
        public ShiroController(ShiroService shiroService) {
            this.shiroService = shiroService;
        }
    
        
        @ApiOperation(value = "登陆", notes = "参数:用户名 密码")
        @PostMapping("/sys/login")
        public Map login(@RequestBody @Validated LoginDTO loginDTO, BindingResult bindingResult) {
            Map result = new HashMap<>();
            if (bindingResult.hasErrors()) {
                result.put("status", 400);
                result.put("msg", bindingResult.getFieldError().getDefaultMessage());
                return result;
            }
    
            String username = loginDTO.getUsername();
            String password = loginDTO.getPassword();
    
    
            //用户信息
            User user = shiroService.findByUsername(username);
    
            //账号不存在、密码错误
            if (user == null || !user.getPassword().equals(password)) {
                result.put("status", 400);
                result.put("msg", "账号或密码有误");
            } else {
                //生成token,并保存到数据库
                result = shiroService.createToken(user.getUserId());
                result.put("status", 200);
                result.put("msg", "登陆成功");
            }
            return result;
        }
    
        
        @ApiOperation(value = "登出", notes = "参数:token")
        @PostMapping("/sys/logout")
        public Map logout(@RequestHeader("token")String token) {
            Map result = new HashMap<>();
            shiroService.logout(token);
            result.put("status", 200);
            result.put("msg", "您已安全退出系统");
            return result;
        }
    }
    
    

    通过自定义过滤器拦截,拒绝访问的请求通过executeLogin方法,校验是否能通过

    **
     * Shiro自定义auth过滤器
     *
     */
    @Component
    public class AuthFilter extends AuthenticatingFilter {
    
    
        // 定义jackson对象
        private static final ObjectMapper MAPPER = new ObjectMapper();
    
        
        @Override
        protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
            //获取请求token
            String token = TokenUtil.getRequestToken((HttpServletRequest) request);
    
            return new AuthToken(token);
        }
    
        
        @Override
        protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
            if (((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name())) {
                return true;
            }
            return false;
        }
    
        
        @Override
        protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
            //获取请求token,如果token不存在,直接返回
            String token = TokenUtil.getRequestToken((HttpServletRequest) request);
            if (StringUtils.isBlank(token)) {
                HttpServletResponse httpResponse = (HttpServletResponse) response;
                httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
                httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtil.getOrigin());
                httpResponse.setCharacterEncoding("UTF-8");
                Map result = new HashMap<>();
                result.put("status", 403);
                result.put("msg", "请先登录");
                String json = MAPPER.writevalueAsString(result);
                httpResponse.getWriter().print(json);
                return false;
            }
            return executeLogin(request, response);
        }
    
        
        @Override
        protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            httpResponse.setContentType("application/json;charset=utf-8");
            httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
            httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtil.getOrigin());
            httpResponse.setCharacterEncoding("UTF-8");
            try {
                //处理登录失败的异常
                Throwable throwable = e.getCause() == null ? e : e.getCause();
                Map result = new HashMap<>();
                result.put("status", 403);
                result.put("msg", "登录凭证已失效,请重新登录");
                String json = MAPPER.writevalueAsString(result);
                httpResponse.getWriter().print(json);
            } catch (IOException e1) {
            }
            return false;
        }
    
    }
    

    查看源码,exeuteLogin内部使用的就是shiro的登录方法

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i8iUuZsq-1640827044142)(C:UsersASUSAppDataRoamingTyporatypora-user-imagesimage-20211229163935965.png)]

    自定义token类要继承UsernamePasswordToken

    public class AuthToken extends UsernamePasswordToken {
    
        private String token;
    
        public AuthToken(String token) {
            this.token = token;
        }
    
        @Override
        public Object getPrincipal() {
            return token;
        }
    
        @Override
        public Object getCredentials() {
            return token;
        }
    }
    
    

    这里不继承 AuthenticationToken,因为getAuthenticationTokenClass()实际上获取到的是UsernamePasswordToken.class

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7A4m85aa-1640827044142)(C:UsersASUSAppDataRoamingTyporatypora-user-imagesimage-20211229164805817.png)]

    九、示例Demo2 (shiro直接处理用户名密码,并实现记住我、md5加密和缓存) 1、用户的角色与权限 用户角色权限adminadmin[查看文件,拷贝文件、移动文件、重命名文件、下载文件、删除文件、上传文件、目录管理、创建目录、文件打分、评论文件、查看得分]lypuser[查看文件,拷贝文件、下载文件、上传文件、目录管理、评论文件、查看得分] 2、编写ShiroConfig
    @Configuration
    public class ShiroConfig {
    
        @Bean(name = "shiroFilter")
        public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
            ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
            shiroFilter.setSecurityManager(securityManager);
            // 登录配置
            shiroFilter.setLoginUrl("/login");
            shiroFilter.setSuccessUrl("/");
            shiroFilter.setUnauthorizedUrl("/error/403");
            // 自定义过滤器
            Map filtersMap = new linkedHashMap<>();
            filtersMap.put("mlfc", new MyLoginFilter());
            shiroFilter.setFilters(filtersMap);
            // 拦截配置
            Map filterChainDefinitions = new linkedHashMap<>();
            filterChainDefinitions.put("/assets
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
            AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
            advisor.setSecurityManager(securityManager());
            return advisor;
        }
    
        
        @Bean
        @DependsOn({"lifecycleBeanPostProcessor"})
        public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
            DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
            advisorAutoProxyCreator.setProxyTargetClass(true);
            return advisorAutoProxyCreator;
        }
    
        
        @Bean("shiroDialect")
        public ShiroDialect getShiroDialect() {
            return new ShiroDialect();
        }
    
        //cookie对象
        @Bean
        public Simplecookie rememberMecookie() {
            Simplecookie simplecookie = new Simplecookie("rememberMe");
            simplecookie.setMaxAge(259200);
            return simplecookie;
        }
    
        //cookie管理对象  处理记住我功能
        @Bean
        public cookieRememberMeManager rememberMeManager() {
            cookieRememberMeManager cookieRememberMeManager = new cookieRememberMeManager();
            cookieRememberMeManager.setcookie(rememberMecookie());
            cookieRememberMeManager.setCipherKey(base64.decode("2AvVhdsgUs0FSA3SDFAdag=="));
            return cookieRememberMeManager;
        }
    }
    
    3、自定义Realm
    public class MyRealm extends AuthorizingRealm {
    
        @Autowired
        private UserMapper userMapper;
    
        @Autowired
        private UserRoleMapper userRoleMapper;
    
        @Autowired
        private RoleAuthMapper roleAuthMapper;
    
        
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            User user = (User) principals.getPrimaryPrincipal();
            SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
            List roleList = userRoleMapper.selectRoleCodesById(user.getId());
            List authList = roleAuthMapper.selectAuthCodesByRoleCodes(roleList);
            Set roleSet = new HashSet<>(roleList);
            Set authSet = new HashSet<>(authList);
            authorizationInfo.setRoles(roleSet);
            authorizationInfo.setStringPermissions(authSet);
            return authorizationInfo;
        }
    
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            String username = (String) token.getPrincipal();
            // 往数据库中查询用户
            User user = userMapper.selectOne(new QueryWrapper().lambda().eq(User::getUsername, username));
            if (user == null) {
                // 账号不存在
                throw new UnknownAccountException();
            }
            // 密码验证shiro处理
            return new SimpleAuthenticationInfo(
                user,  //用户
                user.getPassword(), //密码
                ByteSource.Util.bytes("lyp"),  // 加密传入盐值
                getName());//Realm name
            );
    
        }
    
    }
    
    4、测试接口
    @RestController
    public class ScoreController extends baseController{
    
        @Autowired
        ScoreServiceImpl scoreService;
    
        @Autowired
        UserService userService;
    
        
        @RequiresPermissions("file:score")
        @PostMapping("/addScore")
        public R addScore(Score score){
            System.out.println("获取结果:"+score);
            score.setUserId(getLoginUserId());
            if(scoreService.addScore(score)){
    
                return R.succeed("打分成功");
            }
    
            return R.failed("打分失败");
        }
    
        
        @RequiresPermissions("file:check")
        @GetMapping("/getScore/{fileId}")
        public R getScore(@PathVariable Long fileId){
            Score score = scoreService.queryScoreByFId(fileId);
            return R.succeed(score,"查询成功");
        }
    
    }
    
    5、登录处理
        
        @PostMapping("/login")
        @ResponseBody
        public R login(HttpServletRequest request, String username, String password, String code, boolean rememberMe) {
            if (StringUtil.isBlank(username, password)) {
                return R.failed("账号或密码不能为空");
            }
            String sessionCode = (String) request.getSession().getAttribute("captcha");
            if (code == null || !sessionCode.equals(code.trim().toLowerCase())) {
                return R.failed("验证码不正确");
            }
             //获取当前用户
     		 Subject subject = SecurityUtils.getSubject();
    		 //封装用户的登录数据
             UsernamePasswordToken token = new UsernamePasswordToken(username, password, rememberMe);
                
            try {
                //执行登录方法,如果没有异常就说明OK了
     			subject.login(token);
                return R.succeed("登录成功");
            } catch (UnknownAccountException e) {
                return R.failed("用户不存在");
            } catch (IncorrectCredentialsException e) {
                return R.failed("密码错误");
            } catch (ExcessiveAttemptsException eae) {
                return R.failed(" *** 作频繁,请稍后再试");
            }
        }
    

    欢迎分享,转载请注明来源:内存溢出

    原文地址: http://outofmemory.cn/zaji/5684880.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存