身份验证principals 和 credentials 组合就是用户名/密码。
步骤:
1. 获取当前的 Subject. 调用 SecurityUtils.getSubject();
2. 测试当前的用户是否已经被认证. 即是否已经登录. 调用 Subject 的 isAuthenticated()
3. 若没有被认证, 则把用户名和密码封装为 UsernamePasswordToken 对象
4. 执行登录: 调用 Subject 的 login(AuthenticationToken) 方法.
5. 自定义 Realm 的方法, 从数据库中获取对应的记录, 返回给 Shiro.
6. 由 shiro 完成对密码的比对.
代码演示:
shiro集成spring 配置:https://www.cnblogs.com/xiaoliangup/p/10434372.html
登录页面
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Insert title here</title> </head> <body> <h4>Login Page</h4> <form action="${pageContext.request.contextPath}/toLogin" method="POST"> username: <input type="text" name="username"/> <br><br> password: <input type="password" name="password"/> <br><br> <input type="submit" value="Submit"/> </form> </body> </html>
LoginController实现login处理
@RequestMapping("toLogin") public String toLogin(@PathParam(value="username") String username,@PathParam(value="password") String password){ // get the currently executing user: Subject currentUser = SecurityUtils.getSubject(); // let‘s login the current user so we can check against roles and permissions: if (!currentUser.isAuthenticated()) { UsernamePasswordToken token = new UsernamePasswordToken(username, password); //token.setRememberMe(true); try { currentUser.login(token); } catch (UnknownAccountException uae) { log.info("There is no user with username of " + token.getPrincipal()); } catch (IncorrectCredentialsException ice) { log.info("Password for account " + token.getPrincipal() + " was incorrect!"); } catch (LockedAccountException lae) { log.info("The account for username " + token.getPrincipal() + " is locked. " + "Please contact your administrator to unlock it."); } // ... catch more exceptions here (maybe custom ones specific to your application? catch (AuthenticationException ae) { //unexpected condition? error? } } return "redirect:/list"; }
继承AuthenticatingRealm重写doGetAuthenticationInfo方法,获取数据源,用于与登录用户名、密码的比对
public class SecondRealm extends AuthenticatingRealm { @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { // 1. 把 AuthenticationToken 转换为 UsernamePasswordToken UsernamePasswordToken userToken = (UsernamePasswordToken) token; // 2. 从 UsernamePasswordToken 中来获取 username String username = userToken.getUsername(); // 3. 调用数据库的方法, 从数据库中查询 username 对应的用户记录 System.out.println("从数据库中获取 username: " + username + " 所对应的用户信息."); // 4. 若用户不存在, 则可以抛出 UnknownAccountException 异常 if ("unknown".equals(username)) { throw new UnknownAccountException("用户不存在!"); } // 5. 根据用户信息的情况, 决定是否需要抛出其他的 AuthenticationException 异常. if ("monster".equals(username)) { throw new LockedAccountException("用户被锁定"); } // 6. 根据用户的情况, 来构建 AuthenticationInfo 对象并返回. 通常使用的实现类为: // SimpleAuthenticationInfo // 以下信息是从数据库中获取的. // 1). principal: 认证的实体信息. 可以是 username, 也可以是数据表对应的用户的实体类对象. Object principal = username; // 2). credentials: 密码. Object credentials = null; if ("admin".equals(username)) { credentials = "49d9fbf007fd95343492e607aa34455eeb062b26"; // } else if ("user".equals(username)) { credentials = "effe6046bac27fa7a5a9fc5dcf2d24e03d7f0e3b"; } String realmName = getName(); ByteSource credentialsSalt = ByteSource.Util.bytes(username); SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials,credentialsSalt, realmName); return info; }
用户密码加密处理
1、用户注册时如何实现MD5 盐值加密
1)使用 ByteSource.Util.bytes() 来计算盐值,使用 ByteSource.Util.bytes() 来计算盐值
2)使用 new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations); 来计算盐值加密后的密码的值
public static void main(String[] args) { String hashAlgorithmName = "SHA1"; Object credentials = "1234"; Object salt = ByteSource.Util.bytes("user"); int hashIterations = 1024; Object result = new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
//使用 new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations); //Object result = new SimpleHash(hashAlgorithmName, credentials); System.out.println(result); }
2、为了与注册时实现了MD5 盐值加密的密码进行比对,登录时登录密码也需要进行加密处理,实现比对
1)在 doGetAuthenticationInfo 方法返回值创建 SimpleAuthenticationInfo 对象的时候, 需要使用SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName) 构造器
String realmName = getName(); ByteSource credentialsSalt = ByteSource.Util.bytes(username); SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials,credentialsSalt, realmName);
2)通过 AuthenticatingRealm 的 credentialsMatcher 属性来进行的密码的比对
spring-shiro.xml中的credentialsMatcher配置
<bean id="myRealm" class="org.tarena.shiro.realm.MyRealm"> <property name="credentialsMatcher" > <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> <property name="hashAlgorithmName" value="MD5"></property> <property name="hashIterations" value="1024"></property> </bean> </property> </bean>
原文:https://www.cnblogs.com/xiaoliangup/p/10448144.html