炒干货!!!Springboot整合Shiro实现登录加密和权限

140 篇文章 1 订阅
82 篇文章 0 订阅

这篇文章实打实的技术指导,废话不多说,直接开始干,希望大家多多一键三连支持一下野生技术博客,毕竟这年头技术博士不多见了呀

先看看下面的teacher表

image1.jpeg

role表 image2.png

perms表 image3.png

image4.png

shiro是一个安全框架,可以进行认证、授权、密码加密、会话管理 从外部来解析shiro框架:

image5.png

Subject:主体,代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;即一个抽象概念;所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者;

SecurityManager:安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且它管理着所有Subject;可以看出它是Shiro的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,你可以把它看成DispatcherServlet前端控制器;

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

使用:

引入依赖

</dependency>
<!--Shiro整合-->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.4.0</version>
</dependency> 

其他依赖

<!--thymeleaf依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
    <version>2.1.1.RELEASE</version>
<!--thymeleaf页面使用shiro标签-->
<dependency>
    <groupId>com.github.theborakompanioni</groupId>
    <artifactId>thymeleaf-extras-shiro</artifactId>
    <version>2.0.0</version>
</dependency>
<!--shiro集成ehcache缓存--> 

配置类ShiroConfig和自定义Realm

ShiroConfig初始3个bean

//创建ShiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    //设置安全管理器
    shiroFilterFactoryBean.setSecurityManager(securityManager);

    //添加Shiro内置过滤器
    /*Shiro内置过滤器,实现权限相关的拦截器
    *常用过滤器:
    *   anon:无需认证可以访问
    *   authc:必须认证才可以访问
    *   user:如果使用rememberMe功能可以直接访问
    *   perms:该资源必须得到资源权限才可以访问
    *   role:给资源必须得到角色权限才可以访问
    *
    * */
    Map<String,String> filterMap = new LinkedHashMap<>();
    filterMap.put("/test","anon");
    filterMap.put("/login","anon");
    filterMap.put("/doRegister","anon");
    filterMap.put("/register","anon");
    //授权过滤器
    //当前授权拦截和,shiro自动跳转到未授权页面
    filterMap.put("/add","perms[user:add]");
    filterMap.put("/update","perms[user:update]");
    filterMap.put("/*","authc");
    shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
    //默认跳转到login.jsp,修改为toLogin
    shiroFilterFactoryBean.setLoginUrl("/toLogin");
    //设置未授权页面
    shiroFilterFactoryBean.setUnauthorizedUrl("/unAuth");
    return shiroFilterFactoryBean;
} 
//创建DefaultWebSecurityManager
@Bean("securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    //关联Realm
    securityManager.setRealm(userRealm);
    //
    securityManager.setSessionManager( getDefaultWebSessionManager() );
    return securityManager;
}
//创建Realm
@Bean("userRealm")
public UserRealm getRealm(){
    return new UserRealm();
} 

自定义Realm UserRealm.java

继承: extends AuthorizingRealm
重写两个方法

//执行授权逻辑
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    System.out.println("执行授权");
    return null;
}
//执行认证逻辑
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    System.out.println("执行认证"); 
} 

Ctrl层

Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(name,password); 

登录
subject.login(token);

登出
subject.logout();

权限管理
认证时获取角色,权限

  • List<Role> rlist = rMapper.roleList(login.getRid());//获取用户角色
    List<Perms> plist = pMapper.permList(login.getRid());//获取用户权限
    List<String> roleStrlist=new ArrayList<>();用户的角色集合
    List<String> perminsStrlist=new ArrayList<>();//用户的权限集合
    for (Role role : rlist) {
        roleStrlist.add(role.getRole_name());
    }
    for (Perms uPermission : plist) {
        perminsStrlist.add(uPermission.getPerm());
    }
    login.setRoleStrlist(roleStrlist);
    login.setPerminsStrlist(perminsStrlist);
    授权时添加权限
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    //用户的角色集合
    info.addRoles(teacher.getRoleStrlist());
    //用户的权限集合
    info.addStringPermissions(teacher.getPerminsStrlist());
    
    密码加密
    Shiroconfig类中添加两个bean  ,定义加密方法,注入
    @Bean("hashedCredentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");// 散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashIterations(1024);// 散列的次数,比如散列两次,相当于md5(md5(""));
        hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);//是否16进制
        return hashedCredentialsMatcher;
    }
    /**
    
     * 身份认证 realm
       */
       @Bean("myShiroRealm")
       public UserRealm myShiroRealm(){
       UserRealm myShiroRealm = new UserRealm();
       myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
       System.out.println("myShiroRealm 注入成功");
       return myShiroRealm;
       }
       Realm认证时
       SimpleAuthenticationInfo info = null;
        String realname = getName();
       // 盐值加密,可以用用户名
       ByteSource salt = ByteSource.Util.bytes(tname);
       info = new SimpleAuthenticationInfo(login,login.getPassword(),salt, realname);
       Session session = SecurityUtils.getSubject().getSession();
       session.setAttribute("USER_SESSION", login);
       盐:增加加密的复杂度,增加hash 
    

Shiro中MD5加密方法

ByteSource credentialsSalt01 = ByteSource.Util.bytes("张三");
Object credential = "123456";//密码
String hashAlgorithmName = "MD5";//加密方式
//1024指的是加密的次数
Object simpleHash = new SimpleHash(hashAlgorithmName, credential,
        credentialsSalt01, 1024);
System.out.println("加密后的值----->" + simpleHash)

缓存机制

为什么要用缓存呢?在页面上访问一些需要角色或权限才能访问的url,你会发现每次访问都去数据库拿对应用户拥有的角色权限,试想一下,我每访问一个url,都要去数据库重复拿这些数据,显然是一个不成熟的做法,如果有了缓存,我们只需要查询一次数据库,之后访问url都将从缓存中拿数据而不是数据库,这样数据库压力明显降低,看起来也相对成熟。 添加依赖

Shiroconfig添加bean
@Bean
public EhCacheManager getCacheManager(){
    EhCacheManager ehCacheManager = new EhCacheManager();
    //ehCacheManager.setCacheManagerConfigFile("src\\main\\resources\\shiro-ehcache.xml");
    return ehCacheManager;
}
添加到securityManager
securityManager.setCacheManager(getCacheManager());

重复登录
Shiroconfig配置
//禁止重复登录
// 配置sessionDAO
@Bean(name="sessionDAO")
public MemorySessionDAO getMemorySessionDAO(){
    MemorySessionDAO sessionDAO = new MemorySessionDAO();
    return sessionDAO;
}

//配置shiro session 的一个管理器
@Bean(name = "sessionManager")
public DefaultWebSessionManager getDefaultWebSessionManager(){
    DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
    // 设置session过期时间
    sessionManager.setGlobalSessionTimeout(60*60*1000);
    // 请注意看代码
    sessionManager.setSessionDAO(getMemorySessionDAO());
    //解决url携带jessionid问题
    sessionManager.setSessionIdUrlRewritingEnabled(false);
    return sessionManager;
}

Realm认证时判断删除session
//禁止同时登陆
if( tname.equals( login.getName() ) && md5.equals( login.getPassword() ) ){
    // 获取所有session
    Collection<Session> sessions = sessionDAO.getActiveSessions();
    for (Session session: sessions) {
        Teacher sysUser = (Teacher) session.getAttribute("USER_SESSION");
        // 如果session里面有当前登陆的,则证明是重复登陆的,则将其剔除
        System.out.println("seesion:"+session.getId());
        if( sysUser!=null ){
            if( tname.equals( sysUser.getName() ) ){
                session.setTimeout(0);
            }
        }
    }
} 

其他

//配置ShiroDialect,用于thymeleaf和shiro标签配合使用
@Bean
public ShiroDialect getShiroDialect(){
    return new ShiroDialect();
} 

最后想说的话

程序员到底应该关注哪些技术?

答:这些问题,每天都会有人在群里议论,也会有人经常在群里求工作职位坑。那么我的看法是不要纠结学什么,先学了再说,与其抓住变量(新的技术手段)还不如好好学习,我特别喜欢《暗时间》的一段重视知识的本质:对于程序员来说这一点尤其重要,程序员行业的知识芜杂海量,而且总是在增长变化。很多人感叹跟不上新技术。应对这个问题的办法只能是:抓住不变量。
底层知识永远都不过时。算法数据结构永远都不过时。基本的程序设计理论永远都不过时。良好的编码习惯永远都不过时。分析问题和解决问题的能力永远都不过时。强大的学习能力和旺盛的求知欲永远都不过时。你大脑的思维方式永远都不过时。

参考地址:GitHub

推荐阅读:《前三星程序员被无良HR欺骗,因祸得福竟“意外”拿下字节跳动offer(定薪45K)

更多阅读:《21年GitHub标星19.8k阿里腾讯百度Java面试全套真题解析在互联网火了 ,完整版开放下载

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值