Springboot2.0集成shiro

    科技2022-07-15  106

    Shiro的核心概念介绍

    身份认证流程     首先调用 Subject.login(token) 进行登录,其会自动委托给 Security Manager,调用之前必须通过 SecurityUtils.setSecurityManager() 设置;     SecurityManager 负责真正的身份验证逻辑;它会委托给 Authenticator 进行身份验证;     Authenticator 才是真正的身份验证者,Shiro API 中核心的身份认证入口点,此处可以自定义插入自己的实现;     Authenticator 可能会委托给相应的 AuthenticationStrategy 进行多 Realm 身份验证,默认 ModularRealmAuthenticator 会调用 AuthenticationStrategy 进行多 Realm 身份验证;     Authenticator 会把相应的 token 传入 Realm,从 Realm 获取身份验证信息,如果没有返回 / 抛出异常表示身份验证失败了。此处可以配置多个 Realm,将按照相应的顺序及策略进行访问。

    Realm

        Realm:域,Shiro从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;     也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;     可以把 Realm 看成 DataSource,即安全数据源。如之前的 ini 配置方式将使用 org.apache.shiro.realm.text.IniRealm。    

        一般继承 AuthorizingRealm(授权)即可;其继承了 AuthenticatingRealm(即身份验证),而且也间接继承了 CachingRealm(带有缓存实现)。其中主要默认实现如下:     org.apache.shiro.realm.text.IniRealm:[users] 部分指定用户名 / 密码及其角色;[roles] 部分指定角色即权限信息;     org.apache.shiro.realm.text.PropertiesRealm: user.username=password,role1,role2 指定用户名 / 密码及其角色;role.role1=permission1,permission2 指定角色及权限信息;     org.apache.shiro.realm.jdbc.JdbcRealm:通过 sql 查询相应的信息,     如     “select password from users where username = ?”  获取用户密码,     “select password, password_salt from users where username = ?” 获取用户密码及盐;     “select role_name from user_roles where username = ?” 获取用户角色;     “select permission from roles_permissions where role_name = ?” 获取角色对应的权限信息;     也可以调用相应的 api 进行自定义 sql

      授权

          授权,也叫访问控制,即在应用中控制谁能访问哪些资源(如访问页面/编辑数据/页面操作等)。在授权中需了解的几个关键对象:主体(Subject)、资源(Resource)、权限(Permission)、角色(Role)  

    Springboot集成Shiro

    1.引入Maven依赖

    <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.5.3</version> </dependency>

    2.自定义登录逻辑

    public interface LoginService { User getUserByName(String getMapByName); } @Service public class LoginServiceImpl implements LoginService { @Override public User getUserByName(String getMapByName) { //模拟数据库查询,正常情况此处是从数据库或者缓存查询。 return getMapByName(getMapByName); } /** * 模拟数据库查询 */ private User getMapByName(String userName) { //共添加两个用户,两个用户都是admin一个角色, //wsl有query和add权限,zhangsan只有一个query权限 Permissions permissions1 = new Permissions("1", "query"); Permissions permissions2 = new Permissions("2", "add"); Set<Permissions> permissionsSet = new HashSet<>(); permissionsSet.add(permissions1); permissionsSet.add(permissions2); Role role = new Role("1", "admin", permissionsSet); Set<Role> roleSet = new HashSet<>(); roleSet.add(role); User user = new User("1", "wsl", "123456", roleSet); Map<String, User> map = new HashMap<>(); map.put(user.getUserName(), user); Permissions permissions3 = new Permissions("3", "query"); Set<Permissions> permissionsSet1 = new HashSet<>(); permissionsSet1.add(permissions3); Role role1 = new Role("2", "user", permissionsSet1); Set<Role> roleSet1 = new HashSet<>(); roleSet1.add(role1); User user1 = new User("2", "zhangsan", "123456", roleSet1); map.put(user1.getUserName(), user1); return map.get(userName); } } public class User { private String id; private String userName; private String password; /** * 用户对应的角色集合 */ private Set<Role> roles; public User(String id, String userName, String password, Set<Role> roles) { 。。。。 } 。。。。 } public class Permissions { private String id; private String permissionsName; public Permissions() { } public Permissions(String id, String permissionsName) { this.id = id; this.permissionsName = permissionsName; } } public class Role { private String id; private String roleName; /** * 角色对应权限集合 */ private Set<Permissions> permissions; public Role() { } public Role(String id, String roleName, Set<Permissions> permissions) { this.id = id; this.roleName = roleName; this.permissions = permissions; } }

    3.配置Shiro

    @Configuration public class ShiroConfig { // 将自己的验证方式加入容器 @Bean public CustomRealm myShiroRealm() { CustomRealm myShiroRealm = new CustomRealm(); return myShiroRealm; } // 权限管理,配置主要是Realm的管理认证 @Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myShiroRealm()); return securityManager; } /** * Filter工厂,设置对应的过滤条件和跳转条件 */ @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); Map<String, String> filterMap = new HashMap(); // 登出 filterMap.put("/logout", "logout"); // swagger filterMap.put("/swagger**/**", "anon"); filterMap.put("/webjars/**", "anon"); filterMap.put("/v2/**", "anon"); // 对所有用户认证 filterMap.put("/**", "authc"); // 登录 shiroFilterFactoryBean.setLoginUrl("/login"); // 首页 shiroFilterFactoryBean.setSuccessUrl("/index"); // 错误页面,认证不通过跳转 shiroFilterFactoryBean.setUnauthorizedUrl("/error"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); return shiroFilterFactoryBean; } /** * 加入注解的使用,不加入这个注解不生效 */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } }

    4.客户定义授权和鉴权逻辑

    public class CustomRealm extends AuthorizingRealm { @Autowired private LoginService loginService; /** * 授权 * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { //获取登录用户名 String name = (String) principalCollection.getPrimaryPrincipal(); //根据用户名去数据库查询用户信息 User user = loginService.getUserByName(name); //添加角色和权限 SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); for (Role role : user.getRoles()) { //添加角色 simpleAuthorizationInfo.addRole(role.getRoleName()); //添加权限 for (Permissions permissions : role.getPermissions()) { simpleAuthorizationInfo.addStringPermission(permissions.getPermissionsName()); } } return simpleAuthorizationInfo; } /** * 认证方式 * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { if (authenticationToken.getPrincipal() == null) { return null; } //获取用户信息 String name = authenticationToken.getPrincipal().toString(); User user = loginService.getUserByName(name); if (user == null) { return null; } else { SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name, user.getPassword().toString(), getName()); return simpleAuthenticationInfo; } } }

    5.登录获取权限,配置访问其它接口需要的权限信息

    @RestController public class ControllerTest { //http://localhost:8080/login?userName=wsl&password=123456 @GetMapping("/login") public String login(User user) { //添加用户认证信息 Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getUserName(), user.getPassword()); try { //进行验证,这里可以捕获异常,然后返回对应信息 subject.login(usernamePasswordToken); // subject.checkRole("admin"); // subject.checkPermissions("query", "add"); } catch (AuthenticationException e) { e.printStackTrace(); return "账号或密码错误!"; } catch (AuthorizationException e) { e.printStackTrace(); return "没有权限"; } return "login success"; } /** * 注解验角色和权限 */ @RequiresRoles("admin") @RequiresPermissions("add") @RequestMapping("/index") public String index() { return "index!"; } }

     

    Processed: 0.011, SQL: 8