springboot集成shiro
Shiro和Security其实还是蛮类似的,至少大致的流程是差不多的,区别在于
- shiro通过token来传递前端的数据,而Security通过绑定特定的页面和属性来实现前端数据的传输。
- shiro和Security对数据处理功能的封装方式不一样。
而如果我们需要使用Security,只需要自定义一个AuthorizingRealm,并且将自定义的Realm注入容器,并且设置为DefaultWebSecurityManagerInfo的属性,并将DefaultWebSecurityManagerInfo注入到容器,并且设置为ShiroFilterFactoryBean的属性即可。将ShiroFilterFactoryBean注入到IOC容器。
下面用一个Demo来讲解一下大致流程
-
前端发送请求
<a th:href="@{/user/add}">add</a>
-
拦截请求并处理,需要拦截请求,配置我们的Shiro
package com.lyj.config; import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.LinkedHashMap; import java.util.Map; @Configuration public class ShiroConfig { //整合shiroDialect:用来整和shiro thymeleaf @Bean public ShiroDialect getShiroDialect(){ return new ShiroDialect(); } //1.Realm 授权器注入容器 @Bean public MyRealm myRealm(){ return new MyRealm(); } //2.DefaultWebSecurityManager权限管理器注入容器,在权限管理器加入我们自己的授权器 @Bean public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("myRealm") MyRealm myRealm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //关联realm securityManager.setRealm(myRealm); return securityManager; } //3.ShiroFilterFactoryBean 权限规则设置工厂注入容器,在 @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager securityManager){ ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //设置安全管理器 shiroFilterFactoryBean.setSecurityManager(securityManager); //添加shiro的内置过滤器 /** * anon:无需认证即可访问 * authc:必须认证才可以访问 * user:必须拥有 记住我 才能用 * perms:拥有对某个资源的权限才能访问 * role: 必须拥有某个权限才能访问 * */ Map<String, String> filterMap = new LinkedHashMap<>(); filterMap.put("/user/add","perms[user:add]"); filterMap.put("/user/update","perms[user:update]"); filterMap.put("/user/*","authc"); //filterMap.put("/user/*","authc"); //放入过滤链中 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); //设置登录的请求 shiroFilterFactoryBean.setLoginUrl("/toLogin"); //设置权限验证失败界面 shiroFilterFactoryBean.setUnauthorizedUrl("/noauth"); return shiroFilterFactoryBean; } }
package com.lyj.config; import com.lyj.pojo.User; import com.lyj.service.UserService; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; import org.springframework.beans.factory.annotation.Autowired; //自定义realm public class MyRealm extends AuthorizingRealm { @Autowired private UserService userService; //授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("授权中"); //授权器 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //info.addStringPermission("user:add"); //全部统一加上权限。 //it acquires the Subject based on user data associated with current thread or incoming request. //获取当前线程的用户 Subject subject = SecurityUtils.getSubject(); //Returns this Subject's principals (identifying attributes) in the form of a {@code PrincipalCollection} //获取当前subject的身份属性(之前封装成了token) User user = (User) subject.getPrincipal(); //设置用户当前权限 info.addStringPermission(user.getPerms()); return info; } //从数据库中拿到用户名与密码,并验证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("验证密码中"); //2.得到前端存入的token UsernamePasswordToken token= (UsernamePasswordToken) authenticationToken; User user = userService.queryUserByName(token.getUsername()); if (user==null){ return null; // } SecurityUtils.getSubject() .getSession() .setAttribute("loginUser",user.getName()); //密码认证,shiro做 System.out.println("密码验证中"); return new SimpleAuthenticationInfo(user,user.getPwd(),""); } }
-
将前端的请求进行过滤
Map<String, String> filterMap = new LinkedHashMap<>(); filterMap.put("/user/add","perms[user:add]"); filterMap.put("/user/update","perms[user:update]"); filterMap.put("/user/*","authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
-
若不在过滤规则,放行
若已登陆,无权限访问,跳转到指定页面
shiroFilterFactoryBean.setUnauthorizedUrl("/noauth");
若未登录,跳转到登录页面的请求
shiroFilterFactoryBean.setLoginUrl("/toLogin");
-
定义跳转到登录页面的请求
@RequestMapping("/toLogin") public String toLogin(){ return "login"; }
-
登录页面发送登录请求
<form th:action="@{/login}"> <input name="username" type="text"> <input name="password" type="password"> <input type="submit" value="提交"> </form>
-
定义登录请求(传入参数,封装到token中,调用shiro处理)
@RequestMapping("/login") public String login(String username, String password, Model model){ System.out.println("我刚通过login接口进入"); //获取当前用户 Subject subject = SecurityUtils.getSubject(); //it acquires the Subject based on user data associated with current thread or incoming request. //封装用户数据 System.out.println("封装前端的数据"); UsernamePasswordToken token = new UsernamePasswordToken(username, password); System.out.println("封装完毕"); //执行登录方法 try{ //将封装的信息放入subject并且调用shiro的拦截验证 subject.login(token); return "index"; }catch (UnknownAccountException e){ //用户名不存在 model.addAttribute("msg","用户名不存在"); return "login"; }catch (IncorrectCredentialsException e){ model.addAttribute("msg","密码错误"); return "login"; } }
-
验证用户名是否正确
@Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("验证密码中"); //2.得到前端存入的token UsernamePasswordToken token= (UsernamePasswordToken) authenticationToken; User user = userService.queryUserByName(token.getUsername()); if (user==null){ return null; // } SecurityUtils.getSubject() .getSession() .setAttribute("loginUser",user.getName()); //密码和用户名认证,shiro做 System.out.println("密码验证中"); return new SimpleAuthenticationInfo(user,user.getPwd(),""); }
-
给用户授予权限
//授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("授权中"); //授权器 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //info.addStringPermission("user:add"); //全部统一加上权限。 //it acquires the Subject based on user data associated with current thread or incoming request. //获取当前线程的用户 Subject subject = SecurityUtils.getSubject(); //Returns this Subject's principals (identifying attributes) in the form of a {@code PrincipalCollection} //获取当前subject的身份属性(之前封装成了token) User user = (User) subject.getPrincipal(); //设置用户当前权限 info.addStringPermission(user.getPerms()); return info; }
-
再次经过过滤链过滤请求
Map<String, String> filterMap = new LinkedHashMap<>(); filterMap.put("/user/add","perms[user:add]"); filterMap.put("/user/update","perms[user:update]"); filterMap.put("/user/*","authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
-
请求通过