六安市建设网站市场信息价,在线制作海报网站,苏宁网站建设,大连网站优化快速排名Shiro与Spring Security都是主流的身份认证和权限控制安全框架#xff0c;Shiro偏向于前后端不分离平台#xff0c;而Spring Security更偏向于前后端分离平台。接下来简单列一下两种登录验证的执行流程和示例#xff0c;了解实际运用中的登录执行流程#xff0c;然后重点剖… Shiro与Spring Security都是主流的身份认证和权限控制安全框架Shiro偏向于前后端不分离平台而Spring Security更偏向于前后端分离平台。接下来简单列一下两种登录验证的执行流程和示例了解实际运用中的登录执行流程然后重点剖析一下密码验证的过程。其实密码验证的本质就是比较用户输入的凭证密码和存储的凭证加密后的密码是否匹配 如果一致则表示密码验证通过。 文章目录 Spring Security的登录过程1.导入依赖2.UsernamePasswordAuthenticationToken3.UserDetailsServiceImpl4.账号密码验证说明重点加密说明加密特点不需要提供盐、每次加密结果都不一样加密示例 Shiro的登录过程1.导入依赖2.UsernamePasswordToken3.UserRealm4.账号密码验证说明重点加密说明加密特点需要提供盐、加密的时候需要传入登录用户名、加密结果都是一样的加密示例 Spring Security的登录过程
1.导入依赖 dependencygroupIdorg.springframework.security/groupIdartifactIdspring-security-core/artifactId/dependency2.UsernamePasswordAuthenticationToken
在登录方法中通过UsernamePasswordAuthenticationToken把用户名、密码信息封装起来使用AuthenticationManager的authenticate方法并传入UsernamePasswordAuthenticationToken对象
RestController
public class LoginController {Resourceprivate AuthenticationManager authenticationManager;RequestMapping(/login)public R login(String userName, String password){Authentication authentication null;try {UsernamePasswordAuthenticationToken authenticationToken new UsernamePasswordAuthenticationToken(userName, password);AuthenticationContextHolder.setContext(authenticationToken);// 该方法会去调用UserDetailsServiceImpl.loadUserByUsernameauthentication authenticationManager.authenticate(authenticationToken);} catch (Exception e) {e.printStackTrace();return R.error();}//登录认证成功生成token返回LoginUser loginUser (LoginUser) authentication.getPrincipal();String token getToken(loginUser); return R.ok().setData(token);}private String getToken(LoginUser loginUser) {//TODO 按照自己的业务需求生成return null;}
}上下文对象用来存放身份认证信息
/*** 上下文对象用来存放身份认证信息*/
public class AuthenticationContextHolder {private static final ThreadLocalAuthentication contextHolder new ThreadLocal();public static Authentication getContext() {return contextHolder.get();}public static void setContext(Authentication context) {contextHolder.set(context);}public static void clearContext() {contextHolder.remove();}
}3.UserDetailsServiceImpl
①同时定义UserDetailsServiceImpl类实现UserDetailsService并重写loadUserByUsername方法上面步骤就会执行到此方法中 ②在loadUserByUsername方法中通过上下文传值AuthenticationContextHolder获取到登录的用户名和密码 ③进行账号、密码验证
Service
public class UserDetailsServiceImpl implements UserDetailsService {Autowiredprivate UserService userService;Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User user userService.selectUserByUserName(username);boolean state validate(user); //验证用户信息if (!state) {//账号、密码验证失败throw new UsernameNotFoundException(账号、密码验证失败);}//生成UserDetails信息返回UserDetails userDetails new LoginUser();return userDetails;}private boolean validate(User user){Authentication usernamePasswordAuthenticationToken AuthenticationContextHolder.getContext();String password usernamePasswordAuthenticationToken.getCredentials().toString();//验证账号、密码return new BCryptPasswordEncoder().matches(password, user.getPassword());}
}4.账号密码验证说明重点
加密说明
Spring Security主要使用BCryptPasswordEncoder进行加密的BCryptPasswordEncoder用SHA-256随机盐密钥对密码进行加密这种加密过程中不需要使用密钥输入明文后由系统直接经过加密算法处理成密文这种加密后的数据是无法被解密的无法根据密文推算出明文。BCryptPasswordEncoder的加密过程中同一个密码由于盐是随机的所以每次加密的结果都是不一样的然后就是明文密码的hash值与数据库中存储密码hash值进行比较。
加密特点不需要提供盐、每次加密结果都不一样
加密示例 public static void main(String[] args) {//初始化BCryptPasswordEncoderBCryptPasswordEncoder encoder new BCryptPasswordEncoder();//原始密码String initPwd 123456;String encode1 encoder.encode(initPwd);System.out.println(1次加密结果encode1);String encode2 encoder.encode(initPwd);System.out.println(2次加密结果encode2);String encode3 encoder.encode(initPwd);System.out.println(3次加密结果encode3);boolean b1 encoder.matches(initPwd, encode1);System.out.println(1次加密认证b1);boolean b2 encoder.matches(initPwd, encode2);System.out.println(2次加密认证b2);boolean b3 encoder.matches(initPwd, encode3);System.out.println(3次加密认证b3);}运行结果
1次加密结果$2a$10$8NfgZSeUG8mCApNeJumsg.Z6k3SF1HrGPB0FPuLDlFy2jYF.uHYAm
2次加密结果$2a$10$.PTFbG0qwMHiQLgA5SY/pOOcHCUP7gZQvQYAEv6RRaE0R3Wc9e.hW
3次加密结果$2a$10$YFI4vgXpnYlcfsqpplqJ1OjL8JczZSqYWjL0jIkmggTpe7cSuaaNi
1次加密认证true
2次加密认证true
3次加密认证trueShiro的登录过程
1.导入依赖 dependencygroupIdorg.apache.shiro/groupIdartifactIdshiro-crypto-hash/artifactIdversion1.6.0/version/dependencydependencygroupIdorg.apache.shiro/groupIdartifactIdshiro-core/artifactIdversion1.6.0/version/dependency2.UsernamePasswordToken
通过UsernamePasswordToken这个类会将用户登录信息封装起来生成Token然后通过SecurityUtils下的subject传入token执行登录方法
RestController
public class LoginController {RequestMapping(/login)public R login(String userName, String password){UsernamePasswordToken token new UsernamePasswordToken(userName, password);Subject subject SecurityUtils.getSubject();try {subject.login(token);//验证通过登录成功return R.ok();} catch (AuthenticationException e) {e.printStackTrace();//用户或密码错误验证失败return R.error();}}
}3.UserRealm
①认证器会将Token分解开来分成账号和密码并通过Relam这个桥梁向数据库进行求证 ②然后自定义UserRealm类并继承AuthorizingRealm方法重写doGetAuthenticationInfo方法中就可以从token中获取用户账号、密码信息 ③进行账号、密码验证
public class UserRealm extends AuthorizingRealm {Autowiredprivate UserService userService;Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {//授权方法 TODOreturn null;}Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {//登录方法UsernamePasswordToken upToken (UsernamePasswordToken) authenticationToken;String userName upToken.getUsername();String password new String(upToken.getPassword());//执行登录验证User user null;try {//验证账号、密码user validate(userName, password);} catch (Exception e) {throw new AuthenticationException(e.getMessage(), e);}return new SimpleAuthenticationInfo(user, password, getName());}private User validate(String userName, String password) throws AuthenticationException {User user userService.selectUserByUserName(userName);if (user null) {throw new AuthenticationException(用户不存在);}//输入密码加密String inputPwd encryptPassword(userName, password, user.getSalt());//数据库密码String dbPwd user.getPassword();if (!inputPwd.equals(dbPwd)) {throw new AuthenticationException(用户名、密码验证失败);}return user;}private static String encryptPassword(String userName, String password, String salt) {return new Md5Hash(userName password salt).toHex().toString();}
}4.账号密码验证说明重点
加密说明
Shiro主要使用的是MD5进行加密的底层就是传入登录名、密码、盐使用MD5进行hash加密计算得到一个密文字符串通常会把盐和这个密文字符串存入到数据库中。下次用户登录的时候传入登录名和密码从数据库中获取到盐MD5加密生成此时的加密密文与数据库中存储的加密密文进行匹配。如果一致则验证通过如果不一致则验证不通过。
加密特点需要提供盐、加密的时候需要传入登录用户名、加密结果都是一样的
加密示例 public static void main(String[] args) {//密文密码String dbPwd 3d3e2e119996cedb7401025cced5c1b0;//用户名String userName admin;//盐String salt 111111;//明文密码String inputPwd 123456;String encryptPassword encryptPassword(userName, inputPwd, salt);System.out.println(加密结果encryptPassword);boolean b dbPwd.equals(encryptPassword);System.out.println(认证结果b);}public static String encryptPassword(String userName, String password, String salt) {return new Md5Hash(userName password salt).toHex().toString();}运行结果
加密结果3d3e2e119996cedb7401025cced5c1b0
认证结果true