Springboot2.x整合shrio进行简单的登录、登出与角色鉴权

    xiaoxiao2021-04-15  204

    Springboot2.x整合shrio进行简单的登录、登出与角色鉴权

    首先说明一下,整合shrio主要需要我们独立书写的是配置类与Controller层shrio的核心对象subject,所以这里只贴了配置类与Controller层,而且博主也是才接触到shiro,如果有什么解析的不太对的,还望指出大家一起进步:

    首先需要独立引入依赖:

    <!--导入shrio核心依赖--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.4.0</version> </dependency> <!--这个是阿帕奇老铁的工具类,集合判空很好用,还有很多其他功能,反正爽就对了--> <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>3.2.1</version> </dependency>

    Shrio的配置类之AuthRealm:

    /** * 认证授权的配置类,主要还是与数据源打交道的 */ public class AuthRealm extends AuthorizingRealm { @Autowired private UserService userService; @Override /** * 作为授权使用,需要覆盖这个方法来实现 * */ protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { //授权实际上是在认证登录以后,把获取的User对象放入到了session中 //将session中的user对象取出来,使用的是principals.fromRealm这个方法 //传入的参数是这个类的名字,我们使用迭代器,进行遍历,将其取出 User user= (User) principals.fromRealm(this.getClass().getName()).iterator().next(); //声明权限的集合 List<String> permissionList = new ArrayList<>(); //声明角色的集合 List<String> roleNameList= new ArrayList<>(); //拿到当前所有的角色 Set<Role> roles = user.getRoles(); //遍历所有的角色 //实现判断一下角色集合,只有当角色集合不为空的时候才能进行判断 if (CollectionUtils.isNotEmpty(roles)){ //将角色挨个遍历出来 for (Role role: roles){ //每次遍历角色的时候,将角色名取出来放进提前定义好的角色集合里 roleNameList.add(role.getRname()); //再拿到每个角色的权限列表 Set<Permission> permissions = role.getPermissions(); if ( CollectionUtils.isNotEmpty(permissions)){ for (Permission permission:permissions){ //将每一个权限的name放到我们之前定义好的permissionLiST里 //因为我们本质上还是根据permissionname进行判断一个用户是否有某个权限 permissionList.add(permission.getName()); } } } } //创建实例zationInfo的实例,将我们获取到的权限加入到对象中 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //将权限授权添加给授权信息实例(SimpleAuthorizationInfo) info.addStringPermissions(permissionList); //处理simpleAuthorizationInfo的时候,同样为他加上角色授权 info.addRoles(roleNameList); return info; } @Override /** * 作为认证登录使用,需要覆盖这个方法来实现 */ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { //1.将传入的token强转为shiro的UsernamePasswordToken类型 UsernamePasswordToken usernamePasswordToken=(UsernamePasswordToken) token; //2.从里面取出对应的Username String username = usernamePasswordToken.getUsername(); //3.调用我们之前写过的根据Username查询User实体的方法,得到User实体 User user = userService.findByUserName(username); //4.将用户里的数据转换成AuthenticationInfo对象 //传入参数为:刚查询到的user对象,密码,当前这个类的名字(我们通过反射获得) SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user,user.getPassword(),this.getClass().getName()); //返回就行了 return simpleAuthenticationInfo; } }

    shiro的配置类之CredentialMatcher:

    /** * 继承shrio为我们提供的Matcher接口,从而实现自定义加密规则的功能,然后再将这个类注入到 * AuthRealm中就好 */ public class CredentialMatcher extends SimpleCredentialsMatcher { /** * 覆盖重写默认的Match的方法 * * @param token * @param info * @return */ @Override public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { //将传递过来的token转化成UsernamePasswordToken UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token; //从usernamePasswordToken中取出password //但是这个类返回的值是char型数组,我们需要将其转换成string //这是前端传递过来的密码 String password = new String(usernamePasswordToken.getPassword()); //现在我们需要再拿出我们数据库里的密码,也就是我们刚才为info对象传入的值 String dbpassword = (String) info.getCredentials(); //这样两个密码都有了,中间规则就可以由我们来定义了 //我们这里就直接看它两个是否相同就好了 //这里的this代指的是SimpleCredentialsMatcher对象 return this.equals(password, dbpassword); } }

    shrio核心配置类也是我们主要进行改写的类:

    ** * 将这个类设置为配置类,springboot启动的时候会自动将她加入到我们的容器中 */ @Configuration public class ShiroConfiguraion { /** * 定义shiroFilter,也就是shiro拦截器 * 其中需要的参数为: * 1.manager安全调度管理者(这里暂时来看只是配置了加密规则) * 2.我们自定义的url * 3.还有对url自定义的规则 * @param manager * @return */ @Bean("shiroFilter") public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") SecurityManager manager){ //实例化一个shrio工厂Bean ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean(); //注入我们之前定义的mananger factoryBean.setSecurityManager(manager); //这里之前,基本上前面都是死的,这里就是要配置成我们自己的了 //定义登录的url(页面) factoryBean.setLoginUrl("/login"); //定义登录成功后跳转到的url(页面) factoryBean.setSuccessUrl("/index"); //定义我们没有权限访问的时候跳转的url(页面) factoryBean.setUnauthorizedUrl("/unauthorized"); //配置我们的请求该怎样进行拦截,也就是该使用什么拦截器进行拦截? //key:代表我们访问的请求,value:我们使用什么样的拦截器 LinkedHashMap<String,String> filterChainDefinitionMap = new LinkedHashMap<>(); //举例说明 //第一个参数代表url,第二个代表要求(或者说,如果要访问这个页面需要的权限:比如这里需要用户登录) //其中第二个参数是shrio规定的,我们想要赋予什么权限,就要写shrio个我们规定的语言 //这是DefaultFilter设置的枚举,(可以理解为映射成拦截器)进而对应的不同权限,所以背就好了 filterChainDefinitionMap.put("/index","authc"); //这里是初始登录页面,初始页面就是不需要任何校验,任何人都可以访问,用anon标识 filterChainDefinitionMap.put("/login","anon"); //这里是注册用户的页面,同样设置为谁都可以访问 filterChainDefinitionMap.put("/loginUser","anon"); //设置访问页面的访问权限,这个可以校验角色名称,进而进项权限控制,我们需要先把我们的角色名称放到授权列表里 filterChainDefinitionMap.put("/admin","roles[管理者]"); //这个应该是登录的user用户,谁都可以访问,但是具体的user意思我还不是很理解,,,等等学了之后再更新,, filterChainDefinitionMap.put("/**","user"); //这里我们需要将我们配置的拦截规则赋值给factoryBean factoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); //返回我们自定义的配置bean对象参数为: // 1.manager安全调度管理者(这里暂时来看只是配置了加密规则) // 2.我们自定义的url // 3.还有对url自定义的规则 return factoryBean; } /** * 配置总的安全调度管理者,注意这都是shiro家的东西哦 * @param authRealm * @return */ @Bean("securityManager") public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm){ //创建一个SecurityManager的实例,安全的总调度管理者 DefaultWebSecurityManager manager = new DefaultWebSecurityManager(); //将authRealm放入实例的SecurityManager对象中 manager.setRealm(authRealm); return manager; } /** * 将最下面定义好的密码比较器通过spring的注解传入到这个配置bean中 * * @param matcher * @return */ @Bean("authRealm") public AuthRealm authRealm(@Qualifier("credentialMatcher") CredentialMatcher matcher){ //声明一个authRealm的实例 AuthRealm authRealm = new AuthRealm(); //给出密码比较器 authRealm.setCredentialsMatcher(matcher); //返回我们自己定义的authRealm(可以理解为官方的数据源管理者) return authRealm; } /** * 为配置类创建配置Bean,交给spring容器 * 自定义校验规则 * 也就是密码比较器或者说是采用了什么方式进行加密 * @return */ @Bean("credentialMatcher") public CredentialMatcher credentialMatcher(){ //返回自定义的校验规则 return new CredentialMatcher(); } /** * 配置我们自己定制的shiro与spring的关联 * 这样spring在使用shiro进行操作的时候,就是我们自定义的securityManager * @param securityManager * @return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager){

    Controller层的书写:

    主要还是登录功能,引入了Shiro的核心对象subject的介绍

    jsp页面就省略不写了,不过springboot2整合jsp页面教程网上也一堆,等我以后再写吧基本上就是加依赖建包没啥了

    @Controller public class DemoController { /** * 直接访问login页面 * @return */ @RequestMapping("/login") public String login(){ return "login"; } /** * 登录后的页面 * @return */ @RequestMapping("/index") public String index(){ return "index"; } /** * 初始的登录页面 */ @RequestMapping("/loginUser") public String loginUser(@RequestParam("username") String username, @RequestParam("password") String password, HttpSession session ){ //根据前端传递过来的name和passowrd生成shrio的UsernamePasswordToken UsernamePasswordToken token = new UsernamePasswordToken(username, password); //写shiro的认证逻辑 Subject subject = SecurityUtils.getSubject(); //因为可能出现异常,所以直接try catch try { //调用login方法,传入token subject.login(token); //如果登录没有出现异常的话,就可以通过getPrincinpal()获取登录用户 User user= (User)subject.getPrincipal(); //将登录用户写到session里 session.setAttribute("user",user); //执行成功返回到index页面 return "index"; } catch (AuthenticationException e) { e.printStackTrace(); //出错的话返回登录页面 return "login"; } } /** * 定义一个退出登录的controller * @return */ @RequestMapping("/logout") public String logout() { //同样是通过实例化subject,进行权限与登录登出的逻辑操作 //SecurityUtils 是一个抽象类。并且没有任何子类。在其中声明了一个静态属性,三个静态方法。 //静态属性 securityManager-->用来存储当前应用中全局唯一的一个SecurityManager。 // getSubject 静态方法-->这个是 Shiro 中最核心的方法了,用来获取 Subject. //Subject是Shiro的核心对象,基本所有身份验证、授权都是通过Subject完成 Subject subject = SecurityUtils.getSubject(); if (subject != null) { subject.logout(); } return "login"; } /** * 只有绑定了管理员权限(角色)的用户才能访问admin接口 * 而绑定是在shiroConfiguration里进行的 * @return */ @RequestMapping("/admin") @ResponseBody public String admin() { return "admin success"; } }

    稍微总结一下,如果只看实现的话,我们主要需要运用到shiro的subject对象的各种api,以及shrio核心配置类对不同路径的访问定义不同的权限,至于shrio的延伸,以后应该会更新,另外这里说明一下,这里有好多别人的内容,但是我忘记我学的时候从哪粘贴的了,反正这里先道声抱歉,如果谁看到了可以告诉我,我加一下它的链接

    最后补充一点:IDEA中的mavenhelper插件真好用!!!


    最新回复(0)