shiro实践(1):注册用户密码加密、登录验证及权限验证
shiro是java的安全框架,能方便地实现项目的身份验证、权限验证等相关安全方面的功能。本人用的shiro版本是1.2.3的,当然还是推荐高版本的,功能封装得更完善些。
1.用户注册时,将用户设置的密码加密后存入数据库中(显然密码不能简单地用md5加密一次或者干脆不加密,这些都是会暴露用户隐私的,甚至是触动用户的利益):
1 //生成盐(部分,需要存入数据库中) 2 String random=new SecureRandomNumberGenerator().nextBytes().toHex(); 3 4 //将原始密码加盐(上面生成的盐),并且用md5算法加密三次,将最后结果存入数据库中 5 String result = new Md5Hash("password",random,3).toString();
2.登录验证及权限验证(继承AuthorizingRealm,覆盖其中的方法):
1 @Component 2 public class MyRealM extends AuthorizingRealm { 3 4 5 @Autowired 6 private LoginService loginService; 7 8 /** 9 * 获取用户角色和权限,用于权限认证 10 * @param principals 11 * @return 12 */ 13 @Override 14 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { 15 16 String username = principals.getPrimaryPrincipal().toString(); 17 18 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); 19 //获取角色(从数据库中取出时使用逗号分隔的) 20 UserInfo user = loginService.getUserByName(username); 21 String[] roleArray = user.getUserrole().split(","); 22 23 Set<String> roles = new HashSet<String>(); 24 for (String roleid : roleArray) { 25 roles.add(loginService.getRoles(roleid)); 26 } 27 28 //获取权限(根据角色查询权限表) 29 Set<String> permissions = new HashSet<String>(); 30 for (String roleid : roleArray) { 31 permissions.addAll(loginService.getPermissions(roleid)); 32 } 33 34 info.setRoles(roles); 35 info.setStringPermissions(permissions); 36 return info; 37 } 38 39 /** 40 * 设置用户登录认证 41 * @param token 42 * @return 43 * @throws AuthenticationException 44 */ 45 @Override 46 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 47 //获取输入的用户账号,并通过账号获取相关信息 48 String username = token.getPrincipal().toString(); 49 UserInfo user = loginService.getUserByName(username); 50 if (user != null) { 51 //将查询到的用户账号和密码存放到 authenticationInfo用于后面的权限判断。第三个参数传入用户输入的用户名。 52 SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPwd(), getName()); 53 //设置盐,用来核对密码 54 authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(user.getRandom())); 55 56 return authenticationInfo; 57 } else { 58 return null; 59 } 60 61 } 62 63 64 }
3.shiro增加的配置:
1 <!-- 配置自定义Realm,设定核对密码时在加盐后,要用MD5算法对用户输入的密码加密3次用于核对 --> 2 <bean id="myRealM" class="com.test.shiro.MyRealM"> 3 <property name="credentialsMatcher" > 4 <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> 5 <property name="hashAlgorithmName" value="MD5"></property> 6 <property name="hashIterations" value="3"></property> 7 </bean> 8 </property> 9 </bean> 10 11 12 <!-- 安全管理器 --> 13 <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> 14 <property name="realm" ref="myRealM"/> 15 </bean> 16 17 <!--Shiro过滤器--> 18 <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> 19 <!-- Shiro的核心安全接口,这个属性是必须的 --> 20 <property name="securityManager" ref="securityManager"/> 21 <!-- 身份认证失败,则跳转到登录页面的配置 --> 22 <property name="loginUrl" value="/sourceA/pageA"/> 23 <!-- 权限认证失败,则跳转到指定页面 --> 24 <property name="unauthorizedUrl" value="/sourceA/error"/> 25 <!-- Shiro连接约束配置,即过滤链的定义 --> 26 <property name="filterChainDefinitions"> 27 <value> 28 <!--anon 表示匿名访问,不需要认证以及授权 --> 29 /sourceB=anon 30 <!--authc表示需要认证,没有进行身份认证是不能进行访问的--> 31 /sourceA*=authc 32 <!--roles[内容] 表示需要内容所示的角色才能访问该路径--> 33 /sourceA=roles[user] 34 <!--perms[内容] 表示需要内容所示的权限才能访问该路径--> 35 /sourceC/**=perms["sourceC"] 36 /sourceD/**=authc,perms["sourceD"] 37 38 </value> 39 </property> 40 </bean>
4.登录,调用用户登录验证(权限及角色验证在用户访问某路径时进行拦截):
1 //用户信息bean 2 UserInfo info = new UserInfo(); 3 info.setPwd("password"); 4 info.setUsername("username"); 5 6 Subject subject = SecurityUtils.getSubject(); 7 UsernamePasswordToken token = new UsernamePasswordToken(info.getUsername(), info.getPwd()); 8 9 try { 10 11 //验证 12 subject.login(token); 13 14 //登陆成功后的处理逻辑: 15 System.out.println("登陆成功"); 16 17 } catch (Exception e) { 18 //登陆失败后的处理逻辑: 19 System.out.println("用户名或密码错误"); 20 21 }
5.登出
1 Subject subject = SecurityUtils.getSubject(); 2 if (subject.isAuthenticated()) { 3 subject.logout(); 4 }