shiro学习之路-加密模块
来源:互联网 发布:unity3d像素游戏制作 编辑:程序博客网 时间:2024/06/16 12:38
一.shiro加密模块的使用
1.shiro是主流的权限管理框架,提供了认证,授权,回话管理,密码加密等功能,使得开发者更加便捷
2.具体实现采用MD5加密,而且进行加盐处理
二.代码实现
1.在自定义的认证类中,放回的AuthenticationInfo添加加盐参数
return new SimpleAuthenticationInfo(user,user.getPassword(),credentialsSalt,getName());
import java.util.Set;import org.apache.shiro.authc.AccountException;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.SimpleAuthenticationInfo;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.apache.shiro.util.ByteSource;import org.springframework.beans.factory.annotation.Autowired;import com.yuanjun.shiro.bean.Module;import com.yuanjun.shiro.bean.Role;import com.yuanjun.shiro.bean.User;import com.yuanjun.shiro.service.UserService;/** * * 类名称: MyAuthRealm * 类描述: 自己实现Realm认证授权操作 * @author yuanjun * 创建时间:2017年11月26日下午3:56:12 */public class MyAuthRealm extends AuthorizingRealm{@Autowiredprivate UserService userService;/** * 登陆认证 */protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {//获取登陆信息UsernamePasswordToken token = (UsernamePasswordToken) (authcToken);//获取登录名String username = token.getUsername();//查询数据库中的信息User user = userService.findUserByUserName(username);if(user==null){throw new AccountException("账号不存在");}//使用账号作为盐值ByteSource credentialsSalt = ByteSource.Util.bytes(user.getUsername());return new SimpleAuthenticationInfo(user,user.getPassword(),credentialsSalt,getName());}/** * 授权 */protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {User user = (User) principals.getPrimaryPrincipal();//查找用户对于的角色Set<Role> roles = user.getRoles();//获取权限List<String> permissions=new ArrayList<String>();if(roles.size()>0){for(Role role: roles){Set<Module> module = role.getModules();if(module.size()>0){for (Module module2 : module) {permissions.add(module2.getMname());}}}}SimpleAuthorizationInfo info=new SimpleAuthorizationInfo(); info.addStringPermissions(permissions);//将权限放入shiro中.return info;}}
2.添加密码匹配器
采用的SpringBoot的方式配置,即java配置类注册方式实现,通过跟踪源码的方式getCredentialsMatcher()调用密码匹配器,注册自己的Hash散序管理器,SecurityManager回去调用,传入的数据库的password会与用户输入的密码加盐处理后对比,不正确会抛出异常信息。实现的方式如下,自定义密码匹对,注入到权限登录器
方式一 java代码实现
//配置自定义的权限登录器 @Bean(name="authRealm") public AuthRealm authRealm(@Qualifier("hashedCredentialsMatcher") HashedCredentialsMatcher matcher, EhCacheManager ehCacheManager) { AuthRealm authRealm=new AuthRealm(); authRealm.setCredentialsMatcher(matcher); authRealm.setCacheManager(ehCacheManager); return authRealm; } /** * 密码匹配凭证管理器 * * @return */ @Bean(name = "hashedCredentialsMatcher") public HashedCredentialsMatcher hashedCredentialsMatcher() { HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); hashedCredentialsMatcher.setHashAlgorithmName("MD5");// 散列算法:这里使用MD5算法; hashedCredentialsMatcher.setHashIterations(1024);// 散列的次数,比如散列两次,相当于 // md5(md5("")); return hashedCredentialsMatcher; }
方式二.xml配置
<bean id="jdbcRealm" class="com.java.shiro.realms.ShiroRealm"> <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>
三.源码跟踪过程
1.控制器接受登陆请求,subject.login----自定义认证类的doGetAuthenticationInfo()
public String loginUser(String username,String password,HttpSession session, HttpServletRequest requset,boolean rememberMe) { //加密处理,字符串处理 System.out.println(rememberMe); username = username.trim(); UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken(username,password); Subject subject = SecurityUtils.getSubject(); try { subject.login(usernamePasswordToken); //完成登录 User user=(User) subject.getPrincipal(); session.setAttribute("user", user); return "index"; } catch(Exception e) { requset.setAttribute("err", e.getMessage()); return "login";//返回登录页面 } }
2.doGetAuthenticationInfo()中SimpleAuthenticationInfo--调用父类AuthenticatingRealm getAuthenticationInfo方法
import java.util.Set;import org.apache.shiro.authc.AccountException;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.SimpleAuthenticationInfo;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.apache.shiro.util.ByteSource;import org.springframework.beans.factory.annotation.Autowired;import com.yuanjun.shiro.bean.Module;import com.yuanjun.shiro.bean.Role;import com.yuanjun.shiro.bean.User;import com.yuanjun.shiro.service.UserService;/** * * 类名称: MyAuthRealm * 类描述: 自己实现Realm认证授权操作 * @author yuanjun * 创建时间:2017年11月26日下午3:56:12 */public class MyAuthRealm extends AuthorizingRealm{@Autowiredprivate UserService userService;/** * 登陆认证 */protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {//获取登陆信息UsernamePasswordToken token = (UsernamePasswordToken) (authcToken);//获取登录名String username = token.getUsername();//查询数据库中的信息User user = userService.findUserByUserName(username);if(user==null){throw new AccountException("账号不存在");}//使用账号作为盐值ByteSource credentialsSalt = ByteSource.Util.bytes(user.getUsername());return new SimpleAuthenticationInfo(user,user.getPassword(),credentialsSalt,getName());}/** * 授权 */protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {User user = (User) principals.getPrimaryPrincipal();//查找用户对于的角色Set<Role> roles = user.getRoles();//获取权限List<String> permissions=new ArrayList<String>();if(roles.size()>0){for(Role role: roles){Set<Module> module = role.getModules();if(module.size()>0){for (Module module2 : module) {permissions.add(module2.getMname());}}}}SimpleAuthorizationInfo info=new SimpleAuthorizationInfo(); info.addStringPermissions(permissions);//将权限放入shiro中.return info;}}3.进行认证与用户信息对比
public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { AuthenticationInfo info = getCachedAuthenticationInfo(token); if (info == null) { //otherwise not cached, perform the lookup: info = doGetAuthenticationInfo(token); log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info); if (token != null && info != null) { cacheAuthenticationInfoIfPossible(token, info); } } else { log.debug("Using cached authentication info [{}] to perform credentials matching.", info); } if (info != null) { assertCredentialsMatch(token, info); } else { log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}]. Returning null.", token); } return info; }4.assertCredentialsMatch 调用自定义密码匹配器
protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException { CredentialsMatcher cm = getCredentialsMatcher(); if (cm != null) { if (!cm.doCredentialsMatch(token, info)) { //not successful - throw an exception to indicate this: String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials."; throw new IncorrectCredentialsException(msg); } } else { throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify " + "credentials during authentication. If you do not wish for credentials to be examined, you " + "can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance."); } }采用的SpringBoot的方式配置,即java配置类注册方式实现,通过跟踪源码的方式getCredentialsMatcher()调用密码匹配器,注册自己的Hash散序管理器,SecurityManager回去调用,传入的数据库的password会与用户输入的密码加盐处理后对比,不正确会抛出异常信息。实现的方式如下,自定义密码匹对,注入到权限登录器//配置自定义的权限登录器 @Bean(name="authRealm") public AuthRealm authRealm(@Qualifier("hashedCredentialsMatcher") HashedCredentialsMatcher matcher, EhCacheManager ehCacheManager) { AuthRealm authRealm=new AuthRealm(); authRealm.setCredentialsMatcher(matcher); authRealm.setCacheManager(ehCacheManager); return authRealm; } /** * 密码匹配凭证管理器 * * @return */ @Bean(name = "hashedCredentialsMatcher") public HashedCredentialsMatcher hashedCredentialsMatcher() { HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); hashedCredentialsMatcher.setHashAlgorithmName("MD5");// 散列算法:这里使用MD5算法; hashedCredentialsMatcher.setHashIterations(1024);// 散列的次数,比如散列两次,相当于 // md5(md5("")); return hashedCredentialsMatcher; }private void cacheAuthenticationInfoIfPossible(AuthenticationToken token, AuthenticationInfo info) { if (!isAuthenticationCachingEnabled(token, info)) { log.debug("AuthenticationInfo caching is disabled for info [{}]. Submitted token: [{}].", info, token); //return quietly, caching is disabled for this token/info pair: return; } Cache<Object, AuthenticationInfo> cache = getAvailableAuthenticationCache(); if (cache != null) { Object key = getAuthenticationCacheKey(token); cache.put(key, info); log.trace("Cached AuthenticationInfo for continued authentication. key=[{}], value=[{}].", key, info); } }5.Reaml认证
protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) { if (!realm.supports(token)) { String msg = "Realm [" + realm + "] does not support authentication token [" + token + "]. Please ensure that the appropriate Realm implementation is " + "configured correctly or that the realm accepts AuthenticationTokens of this type."; throw new UnsupportedTokenException(msg); } AuthenticationInfo info = realm.getAuthenticationInfo(token); if (info == null) { String msg = "Realm [" + realm + "] was unable to find account data for the " + "submitted AuthenticationToken [" + token + "]."; throw new UnknownAccountException(msg); } return info; }protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException { assertRealmsConfigured(); Collection<Realm> realms = getRealms(); if (realms.size() == 1) { return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken); } else { return doMultiRealmAuthentication(realms, authenticationToken); } }6.认证信息处理
public final AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException { if (token == null) { throw new IllegalArgumentException("Method argumet (authentication token) cannot be null."); } log.trace("Authentication attempt received for token [{}]", token); AuthenticationInfo info; try { info = doAuthenticate(token); if (info == null) { String msg = "No account information found for authentication token [" + token + "] by this " + "Authenticator instance. Please check that it is configured correctly."; throw new AuthenticationException(msg); } } catch (Throwable t) { AuthenticationException ae = null; if (t instanceof AuthenticationException) { ae = (AuthenticationException) t; } if (ae == null) { //Exception thrown was not an expected AuthenticationException. Therefore it is probably a little more //severe or unexpected. So, wrap in an AuthenticationException, log to warn, and propagate: String msg = "Authentication failed for token submission [" + token + "]. Possible unexpected " + "error? (Typical or expected login exceptions should extend from AuthenticationException)."; ae = new AuthenticationException(msg, t); } try { notifyFailure(token, ae); } catch (Throwable t2) { if (log.isWarnEnabled()) { String msg = "Unable to send notification for failed authentication attempt - listener error?. " + "Please check your AuthenticationListener implementation(s). Logging sending exception " + "and propagating original AuthenticationException instead..."; log.warn(msg, t2); } } throw ae; } log.debug("Authentication successful for token [{}]. Returned account [{}]", token, info); notifySuccess(token, info); return info; }public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException { AuthenticationInfo info; try { info = authenticate(token); } catch (AuthenticationException ae) { try { onFailedLogin(token, ae, subject); } catch (Exception e) { if (log.isInfoEnabled()) { log.info("onFailedLogin method threw an " + "exception. Logging and propagating original AuthenticationException.", e); } } throw ae; //propagate } Subject loggedIn = createSubject(token, info, subject); onSuccessfulLogin(token, info, loggedIn); return loggedIn; }7、登陆信息的保存至principals于session保存
public void login(AuthenticationToken token) throws AuthenticationException { clearRunAsIdentitiesInternal(); Subject subject = securityManager.login(this, token); PrincipalCollection principals; String host = null; if (subject instanceof DelegatingSubject) { DelegatingSubject delegating = (DelegatingSubject) subject; //we have to do this in case there are assumed identities - we don't want to lose the 'real' principals: principals = delegating.principals; host = delegating.host; } else { principals = subject.getPrincipals(); } if (principals == null || principals.isEmpty()) { String msg = "Principals returned from securityManager.login( token ) returned a null or " + "empty value. This value must be non null and populated with one or more elements."; throw new IllegalStateException(msg); } this.principals = principals; this.authenticated = true; if (token instanceof HostAuthenticationToken) { host = ((HostAuthenticationToken) token).getHost(); } if (host != null) { this.host = host; } Session session = subject.getSession(false); if (session != null) { this.session = decorate(session); } else { this.session = null; } }最后回到控制器
public String loginUser(String username,String password,HttpSession session, HttpServletRequest requset,boolean rememberMe) { //加密处理,字符串处理 System.out.println(rememberMe); username = username.trim(); UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken(username,password); Subject subject = SecurityUtils.getSubject(); try { subject.login(usernamePasswordToken); //完成登录 User user=(User) subject.getPrincipal(); session.setAttribute("user", user); return "index"; } catch(Exception e) { requset.setAttribute("err", e.getMessage()); return "login";//返回登录页面 } }
阅读全文
0 0
- shiro学习之路-加密模块
- shiro之编码/加密
- shiro之编码/加密
- python学习之路(hashlib模块----加密)
- shiro 框架之编码/加密
- Shiro之加密方式-yellowcong
- shiro学习之路——shiro简介
- shiro学习之路(1)---初识shiro(Hello Word)
- shiro学习之路(3)----自定义Realm
- shiro学习之路(5)------集成Web
- Shiro学习之身份验证
- Shiro学习之HelloWord
- Shiro学习之JdbcRealm
- Shiro学习(5)编码、加密
- Shiro学习(5)编码、加密
- Apache shiro 笔记整理之加密
- SpringBoot+Shiro学习之密码加密和登录失败次数限制
- Shiro加密
- 接口和抽象类
- css3画五角星
- Android程序生成步骤
- BZOJ2438: [中山市选2011]杀人游戏
- 树形dp小结——1
- shiro学习之路-加密模块
- Python学习记录总结
- 流程控制
- PAT乙级1004. 成绩排名 (20)
- MyBatis-plus在eclipse中的使用详解
- 6.10水仙花数
- 为什么某些Win32技术在Windows NT服务中行为不当?
- 一日一文(8)
- 张小龙分享的产品经验