网站建设岗位职责怎么写,成都工商注册,外贸圈app,桂林漓江在哪个位置关于csmall-passport项目
此项目主要用于实现“管理员”账号的后台管理功能#xff0c;主要实现#xff1a;
管理员登录添加管理员删除管理员显示管理员列表启用 / 禁用管理员
关于RBAC
RBAC#xff1a;Role-Based Access Control#xff0c;基于角色的访问控制
在涉及…关于csmall-passport项目
此项目主要用于实现“管理员”账号的后台管理功能主要实现
管理员登录添加管理员删除管理员显示管理员列表启用 / 禁用管理员
关于RBAC
RBACRole-Based Access Control基于角色的访问控制
在涉及权限管理的应用软件设计中应该至少需要设计以下3张数据表
用户表角色表权限表
并且还至少需要2张关联表
用户与角色的关联表角色与权限的关联表
关于Spring Security框架
Spring Security主要解决了认证与授权相关的问题。
认证判断某个账号是否允许访问某个系统简单来说就是验证登录
授权判断是否允许已经通过认证的账号访问某个资源简单来说就是判断是否具有权限执行某项操作
添加依赖
在基于Spring Boot的项目中使用Spring Security需要添加依赖项
!-- Spring Boot Security依赖项用于处理认证与授权相关的问题 --
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-security/artifactId
/dependency当在项目中添加以上依赖项后你的项目会发生以下变化Spring Boot中的Spring Security的默认行为 所有的请求都是必须要登录才允许访问的包括错误的URL 提供了默认的登录页面当未登录时会自动重定向到此登录页面 提供了临时的登录账号用户名是user密码是启动项目时在控制台中的UUID值每次重启项目都会不同 当登录成功后将自动重定向到此前尝试访问的URL如果此前没有尝试访问某个URL则重定向到根路径可以通过 /logout 路径访问到“退出登录”的页面以实现登出当登录成功后POST请求都是不允许的而GET请求是允许的
关于Spring Security的配置类
在项目的根包下创建config.SecurityConfiguration类继承自WebSecurityConfigurerAdapter类在类上添加Configuration注解
Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
}然后在类中重写void configure(HttpSecurity http)方法
Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {Overrideprotected void configure(HttpSecurity http) throws Exception {}}**注意**在重写的方法中不要使用super调用父类的此方法
由于没有调用父类此方法再次重启项目后与此前将有些不同
所有请求都不再要求登录登录、登出的URL不可访问
关于登录表单
在Spring Security配置类的configure(HttpSecurity http)方法中根据是否调用了参数对象的formLogin()方法决定是否启用登录表单页/login和登出页/logout例如
Override
protected void configure(HttpSecurity http) throws Exception {// 调用formLogin()表示启用登录表单页和登出页如果未调用此方法则没有登录表单页和登出页http.formLogin();
}关于URL的访问控制
在Spring Security配置类的configure(HttpSecurity http)方法中
// 白名单
// 使用1个星号表示通配此层级的任意资源例如/admin/*可以匹配 /admin/delete、/admin/add-new
// 但是不可以匹配多个层级例如/admin/*不可以匹配 /admin/9527/delete
// 使用2个连续的星号表示通配任何层级的任意资源例如/admin/**可以匹配 /admin/delete、/admin/9527/delete
String[] urls {/doc.html,/**/*.js,/**/*.css,/swagger-resources,/v2/api-docs
};// 配置URL的访问控制
http.authorizeRequests() // 配置URL的访问控制.mvcMatchers(urls) // 匹配某些URL.permitAll() // 直接许可即不需要通过认证就可以直接访问.anyRequest() // 任何请求.authenticated(); // 以上配置的请求需要是通过认证的使用临时的自定义账号实现登录
可以自定义类实现UserDetailsService接口并保证此类是组件类则Spring Security框架会基于此实现类来处理认证。
在项目的根包下创建security.UserDetailsServiceImpl类实现UserDetailsService接口并在类上添加Service注解重写接口中定义的抽象方法
Service
public class UserDetailsServiceImpl implements UserDetailsService {Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {return null;}
}当项目中存在UserDetailsService类型的组件对象时尝试登录时Spring Security会自动使用登录表单提交过来的用户名来调用以上loadUserByUsername()方法并得到UserDetails类型的对象此对象中应该包含用户的相关信息例如密码、账号状态等接下来Spring Security会自动使用登录表单提交过来的密码与UserDetails中的密码进行对比且判断账号状态以决定此账号是否能够通过认证。
所以重写以上方法
Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {// 假设存在可用的账号信息用户名root密码123456if (root.equals(s)) {UserDetails userDetails User.builder().username(root).password(123456).disabled(false).accountLocked(false).accountExpired(false).credentialsExpired(false).authorities(暂时给个山寨权限暂时没有作用只是避免报错而已).build();return userDetails;}return null;
}**提示**当项目中存在UserDetailsService类型的组件对象时Spring Security框架不再提供临时的账号用户名为user密码为启动项目时的UUID值的账号
**注意**Spring Security在处理认证时要求密码必须经过加密码处理即使你执意不加密也必须明确的表示出来
在SecurityConfiguration中通过Bean方法配置PasswordEncoder并返回NoOpPasswordEncoder的对象表示“不对密码进行加密处理”
Bean
public PasswordEncoder passwordEncoder() {return NoOpPasswordEncoder.getInstance();
}完成后重启项目通过/login可以测试访问。
使用数据库中的账号数据实现登录
需要实现“根据用户名查询用户的登录信息”需要执行的SQL语句大致是
select id, username, password, enable from ams_admin where username?在项目的根包下创建pojo.vo.AdminLoginInfoVO类
Data
public class AdminLoginInfoVO implements Serializable {private Long id;private String username;private String password;private Integer enable;
}在AdminMapper.java接口中添加抽象方法
AdminLoginInfoVO getLoginInfoByUsername(String username);在AdminMapper.xml中配置以上抽象方法映射的SQL
select .../selectsql/sqlresultMap/resultMap在AdminMapperTests中编写并执行测试 接下来在UserDetailsServiceImpl中先自动装配AdminMapper对象然后调整loadUserByUsername()方法
Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {// 使用参数s作为参数调用AdminMapper对象的getLoginInfoByUsername()方法执行查询// 判断查询结果是否为null// 是无此用户名对应的账号信息返回null// 返回UserDetails对象// username来自查询结果// password暂时写死为123456后续再改成来自查询结果// disable来自查询结果中的enable判断enable是否为0// accountExpired等参考此前的Demo将各值写死
}完成后可以使用数据库中的账号测试登录暂时不方便测试密码。 tLoginInfoByUsername()方法执行查询 // 判断查询结果是否为null // 是无此用户名对应的账号信息返回null
// 返回UserDetails对象
// username来自查询结果
// password暂时写死为123456后续再改成来自查询结果
// disable来自查询结果中的enable判断enable是否为0
// accountExpired等参考此前的Demo将各值写死} 完成后可以使用数据库中的账号测试登录暂时不方便测试密码。#### 密码为什么需要加密如果未加密将密码的原文原始密码直接存入到数据库中可以被轻松获取账户的关键信息以目前主流的网络结构和技术通常密码加密主要防范的是内部工作人员能够接触到服务器的人员需要注意即使密码加密了也要防范相关的内部工作人员例如程序员#### 如何对密码进行加密直接使用现有的某种算法也就是说不会自行设计某个算法#### 使用什么算法对密码进行加密一定**不可以**使用**加密算法**因为所有加密算法都是可以被逆向运算的也就是说可以根据加密得到的结果进行反向运算还原出原始密码通常加密算法仅用于保障数据在传输过程中的安全在对密码进行加密处理并存入到数据库中时应该使用**不可逆**的算法许多**哈希算法**或基于哈希算法的**消息摘要算法**都是不可逆的#### 关于消息摘要算法典型的消息摘要算法有- SHASecure Hash Algorithm家族算法- SHA-1160位算法- SHA-256256位算法- SHA-384384位算法- SHA-512512位算法
- MDMessage Digest系列算法- MD2128位算法- MD4128位算法- MD5128位算法消息摘要算法原本是用于验证接收方所接收的数据与发送方所发出的数据是否一致。消息摘要算法有几个典型特征- 如果消息相同则摘要一定相同
- 如果消息不同则摘要极大概率会不同- 必然存在n个不同的消息摘要完全相同
- 使用同一种算法时无论消息长度是多少摘要的长度是固定的#### 在项目中使用MD5算法在Spring框架中提供了DigestUtils可以非常便利的使用MD5算法将消息处理为摘要java
public class Md5Tests {Testvoid encode() {String rawPassword 123456;String encodedPassword DigestUtils.md5DigestAsHex(rawPassword.getBytes());System.out.println(原文 rawPassword);System.out.println(密文 encodedPassword);}}算法位数对安全性的影响
以MD5算法为例它是128位的算法即其运算结果是由128个二进制位组成的所以其运算结果的排列组件有2的128次方种这个数字转换成十进制是340282366920938463463374607431768211456。
理论上使用MD5算法时要想找到2个不同的消息运算出相同的摘要概率应该是340282366920938463463374607431768211456分之1或者也可以认为你至少需要运算340282366920938463463374607431768211456次才可以找到2个不同的消息运算出相同的摘要。
相比之下更高位数的算法理论上更难找出不同的消息运算出相同的摘要
一般情况下由于MD5的安全系数已经较高所以不一定需要使用位数更高的算法
关于消息摘要算法的破解 – 学术
当2个不同的消息运算出相同的摘要从学术上称之为“碰撞”。
理论上128位的算法其碰撞概率应该是2的128次方分之1。
关于消息算法的破解主要是研究其碰撞概率是否可以使用更少次数的运算实现碰撞而不是尝试根据摘要进行逆向运算还原出消息
目前SHA-1算法已经被视为不安全的算法它是160位算法经过研究只需要经过2的60几次方的运算就可以发生碰撞即SHA-1的安全系数与60几位的算法几乎相当。
关于消息摘要算法的“破解” – 根据摘要得到消息
网上有许多平台可以做到“根据密文还原出原文”这些平台都是记录大量的原文与密文的对应关系当尝试“破解”时本质上是在做查询操作大概是
select 原文 from 数据表 where 密文?例如某平台明确的说明了
本站针对md5、sha1、sha256等全球通用公开的加密算法进行反向查询通过穷举字符组合的方式创建了明文密文对应查询数据库创建的记录约90万亿条占用硬盘超过500TB查询成功率95%以上很多复杂密文只有本站才可查询。本站专注于各种公开算法已稳定运行17年。如果密码可以使用全部的可打印字符7位长度的密码的排列组合有约70万亿种8位长度的密码的排列组件在此基础上需要乘以95则以上平台不可能记录8位长度的所有明文密文的对应关系也就是说只要原始密码的长度达到8位这些平台就可能无法根据密文查询出原文原始密码的长度越长或原始密码的强度越高由多种元素组成例如大小写字母、数字、标点符号被这些平台收录的可能性就越低
如何进一步保障用户的密码安全 – 加盐
盐值的本质就只是一个外部人员很难预测到的字符串它将作用于处理加密过程中例如
// 以下1行定义了盐值
String salt fsd4W87i78oiAsUu43IEF;String rawPassword 123456;
String encodedPassword DigestUtils.md5DigestAsHex((rawPassword salt).getBytes());
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ 将原始密码和盐值一起被处理System.out.println(原文 rawPassword);
System.out.println(密文 encodedPassword);当然盐值应该如何使用也没有明确的规定你可以
String encodedPassword DigestUtils.md5DigestAsHex((rawPassword salt).getBytes());或者
String encodedPassword DigestUtils.md5DigestAsHex((salt rawPassword).getBytes());甚至
String encodedPassword DigestUtils.md5DigestAsHex((salt rawPassword salt rawPassword salt salt).getBytes());总而言之使用盐的目的是”使得被MD5运算的原始数据变得更加复杂“。
你甚至可以使用随机的盐值例如
String salt UUID.randomUUID().toString(); // 使用UUID作为盐值
String rawPassword 123456;
String encodedPassword DigestUtils.md5DigestAsHex((rawPassword salt).getBytes());使用随机盐时必须注意你需要将随机的盐值保存下来否则后续你将无法验证密码
至于如何保存方式有许多例如在数据表中添加新的字段来保存盐值或者把盐值直接作为密码的一部分例如
String salt UUID.randomUUID().toString();
String rawPassword 123456;
String encodedPassword DigestUtils.md5DigestAsHex((rawPassword salt).getBytes()) salt;
System.out.println(盐值 salt);
System.out.println(原文 rawPassword);
System.out.println(密文 encodedPassword);密码加密原则 – 小结
关于密码加密处理
不可以使用加密算法只能使用消息摘要算法或其它哈希算法 不建议使用SHA-1 应该要求用户使用更长的、强度更高的密码避免容易被反查根据密文查询得到原文应该进行加盐处理你还可以使用多重加密使用同一个算法或不同算法对数据进行反复运算可以考虑使用位数更长的算法在MD5的基础上改为使用SHA-256 / SHA-384 / SHA-512
**注意**无论你综合使用以上哪些做法最终可能都无法避免内部人员泄密算法、加密参数、加密过程、密文都是破解时的已知条件导致的穷举式的暴力破解而BCrypt算法是被设计得运算效率极低的算法可以非常有效的避免被暴力破解。