240
世界上有2种人,一种懂二进制,另一种不懂二进制。

关于登录-Sha256Hash+salt 秘密 jwt Token

登录有很多种实现方式参考以下文章

https://zhuanlan.zhihu.com/p/508886081

https://blog.csdn.net/weixin_42193813/article/details/110943055

简单描述一下登陆的流程:

1、登录一开始先请求验证码,后端响应codeImg和codekey

             

2、前端 From 表单填写用户名和密码,还有验证码、

            

 

 

 

3、数据通过网络协议Tcp三次握手建立与服务器通道,传给服务器

            

             服务器3.1校验验证码,3.2查库,3.3解密校验密码,3.4根据user的id 通过JWT生成Token和Expire返回响应

            

    3.1验证码校验是用 uuid 和 captcha校验的,此处uuid就是请求验证码响应的codeKey

            

    3.2查库

    3.3密码

            user.getPassword().equals(new Sha256Hash(form.getPassword(), user.getSalt()).toHex())

.   3.4、返回用户认证Token

4.跳转 info请求 系统拦截token信息进行用户认证

关于密码加密

常见加密算法
对称加密算法:DES、3DES、DESX、Blowfish、IDEA、RC4、RC5、RC6和AES

非对称加密算法:RSA、ECC(移动设备用)、Diffie-Hellman、El Gamal、DSA(数字签名用)

Hash算法:MD2、MD4、MD5、HAVAL、SHA、SHA-1、HMAC、HMAC-MD5、HMAC-SHA1(是一种不可逆的算法)
在线hash计算地址

SHA-256:
对于任意长度的消息,SHA256都会产生一个256位的哈希值,称作消息摘要。这个摘要相当于是个长度为32个字节的数组,通常有一个长度为64的十六进制字符串来表示,其中1个字节=8位,一个十六进制的字符的长度为4位。

  System.out.println(DigestUtils.sha256Hex("123456"));
  System.out.println(new Sha256Hash("123456"));
 // 输出
8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92

  

加盐
散列算法一般用于生成数据的摘要信息,是一种不可逆的算法,一般适合存储密码之类的数据,常见的散列算法如MD5、SHA等。
一般进行散列时最好提供一个salt(盐),比如加密密码“admin”,产生的散列值是“21232f297a57a5a743894a0e4a801fc3”,可以到一些md5解密网站很容易的通过散列值得到密码“admin”,即如果直接对密码进行散列相对来说破解更容易,此时我们可以加一些只有系统知道的干扰数据,如用户名和ID(即盐);这样散列的对象是“密码+用户名+ID”,这样生成的散列值相对来说更难破解

String md5 = new Md5Hash(str, salt).toString();//还可以转换为 toBase64()/toHex()   
String sha1 = new Sha256Hash(str, salt).toString();  

// 保存密码
 String salt = RandomStringUtils.randomAlphanumeric(20);
 user.setPassword(new Sha256Hash(newPassword, salt).toHex());
 user.setSalt(salt);
 // 验证密码
 user.getPassword().equals(new Sha256Hash(form.getPassword(), user.getSalt()).toHex())
 

用户安全Tokoen

根据用户的id生成一个tonken 密钥

 

 登录

 

 

 登录成功调用 info 接口认证你的账号信息,认证就要用到 Shiro

拦截到系统token,并返回token对应用户信息

SysUserEntity userEntity = (SysUserEntity) SecurityUtils.getSubject().getPrincipal();

 

getPrincipal() 如下解释

 

 

认证与授权介绍
首先,需要强调一下,每个权限框架的核心功能就是 认证,与授权,如果读者有着2个概念,学习权限相关的知识将会无比简单;

简单说下认证,认证就是你给服务端一段信息,这段信息服务端收到会跟之前你注册的信息进行比对,比如在无任何加密的情况下将 账号 , 密码 输入 form表单发送请求到服务端,服务端根据你之前注册的账号密码进行比对,如果比对成功,说明认证成功,否则认证失败;复杂一点的认证就是 将你的账号 ,密码进行封装为另一种形式通常称为凭证,签名之类, 再将这种形式凭证的东西发给你,然后每次请求你都带上凭证而后端根据你发送的凭证信息进行解密比对,比对成功就说明认证成功,否则认证失败;

简单说下授权,现在的权限设计基本都是基于 用户 角色 , 权限 方式进行设计, 故一个用户拥有什么样的权限都基于拥有什么样的角色,我们可以给每个角色赋予不同的权限,然后认证成功之后就可以给用户进行授权(也就是将用户拥有的角色,权限返回出去就ok,每次请求的时候附带上权限信息即可,服务端再根据附带的权限信息进行判别);
Shiro的架构及结构

 

认证流程:大致的认证流程是其实我们经常使用的没这么复杂, 首先就是 用户发送请求 , 我们拦截请求,在将请求 信息 通过 security manager , 其 内部就到了 Realm 进行 认证 与授权, 最后将请求到达服务端,服务端封装好数据返回给前端;

 shiro配置如下
ShiroFilterFactoryBean 是配置拦截器,用户拦截url, anno 表示匿名,任何用户都可以访问; authc表示授权,需要拥有授权信息的用户才可以访问,
SecurityManager 是主体管理器,管理许多的主体,并且需要将我们实现的Realm注入其中,进行认证与授权;
ShiroRealm 注入了HashedCredentialsMatcher ,也就是产生凭证的地方,其加密方式与需与用户注册时的方式一致,否则会在Realm中认证失败;
AuthorizationAttributeSourceAdvisor ,APO支持,主要是需要使用到 @RequiresRoles, @RequiresPermissions注解的时候 才起作用;
LifecycleBeanPostProcessor ,Shiro bean的生命周期,看官网的意思是AuthorizationAttributeSourceAdvisor 的实现要基于其才

/**
 * 认证
*/相当于ShiroRealm  @Component public class OAuth2Realm extends AuthorizingRealm { @Autowired private ShiroService shiroService; @Autowired private SysUserTokenDao sysUserTokenDao; @Resource private JwtUtils jwtUtils; @Override public boolean supports(AuthenticationToken token) { return token instanceof OAuth2Token; } /** * 授权(验证权限时调用) */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { SysUserEntity user = (SysUserEntity) principals.getPrimaryPrincipal(); Long userId = user.getId(); //用户权限列表 Set<String> permsSet = shiroService.getUserPermissions(userId); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.setStringPermissions(permsSet); return info; } /** * 认证(登录时调用) */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String accessToken = (String) token.getPrincipal(); if (StringUtils.isNotBlank(accessToken)) { jwtUtils.isTokenExpired(accessToken); } // 验证 token Claims claims = null; try { claims = jwtUtils.analyseToken(accessToken); } catch (Exception e) { throw new IncorrectCredentialsException("token失效,请重新登录"); } boolean tokenExpired = jwtUtils.isTokenExpired(claims); if (tokenExpired) { throw new SevenmeException("登录过期, 请重新登录"); } //查询用户信息 String subject = claims.getSubject(); SysUserEntity user = shiroService.queryUser(Long.parseLong(subject)); // SysUserEntity user = shiroService.queryUser(tokenEntity.getUserId()); //账号锁定 if (user.getStatus() == 0) { throw new LockedAccountException("账号已被锁定,请联系管理员"); } SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, accessToken, getName()); return info; } }

  

/**
 * Shiro配置
 */
@Configuration
public class ShiroConfig {

    @Bean("securityManager")
    public SecurityManager securityManager(OAuth2Realm oAuth2Realm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(oAuth2Realm);
        securityManager.setRememberMeManager(null);
        return securityManager;
    }

    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);

        //oauth过滤
        Map<String, Filter> filters = new HashMap<>();
        // filters.put("oauth2", new OAuth2Filter());
        shiroFilter.setFilters(filters);

        Map<String, String> filterMap = new LinkedHashMap<>();
        filterMap.put("/webjars/**", "anon");
        filterMap.put("/druid/**", "anon");
        filterMap.put("/sys/login", "anon");
        filterMap.put("/swagger/**", "anon");
        filterMap.put("/v2/api-docs", "anon");
        filterMap.put("/swagger-ui.html", "anon");
        filterMap.put("/swagger-resources/**", "anon");
        filterMap.put("/captcha.jpg", "anon");
        filterMap.put("/aaa.txt", "anon");

        filterMap.put("/app/miniotest/**", "anon");
        filterMap.put("/app/miniocontroller/**", "anon");



        // <!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边
        // filterMap.put("/**", "oauth2");

        shiroFilter.setFilterChainDefinitionMap(filterMap);

        return shiroFilter;
    }

    @Bean("lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

} 
posted @ 2022-10-28 15:20  _Origin  阅读(900)  评论(0编辑  收藏  举报