- 一步一步教你用shiro——1引入shiro框架
- 一步一步教你用shiro——2配置并自定义realm
- 一步一步教你用shiro——3配置并自定义sessionManager
- 一步一步教你用shiro——4配置并自定义sessionDao
- 一步一步教你用shiro——5配置rememberMe
- 一步一步教你用shiro——6总结和心得
CREATE TABLE IF NOT EXISTS `user` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`user_name` varchar(10) NOT NULL DEFAULT '' COMMENT '用户名',
`password` varchar(50) NOT NULL DEFAULT '' COMMENT '用户密码,用户名为盐,五次md5',
`roles` varchar(20) NOT NULL DEFAULT '' COMMENT '角色名,逗号分隔',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uniq_idx_role_name` (`user_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
- 实现dao增删改查(使用的mybatis代理dao),封一个service实际操作user表
@Service
public class UserService {
@Resource
private UserDao userDao;
public User queryUserByName(String name) {
try {
if (StringUtils.isBlank(name)) {
return null;
}
return userDao.queryUserByName(name);
} catch (Exception e) {
log.error("db error when query user:{}", name, e);
}
return null;
}
public Set<String> queryUserRole(String userName) {
User user = queryUserByName(userName);
if (user == null) {
return Collections.emptySet();
}
List<String> roleList = StringAssist.splitComma(user.getRoles());
return Sets.newHashSet(roleList);
}
}
- 自定义MyRealm继承AuthorizingRealm,分别实现认证和授权的方法
- doGetAuthenticationInfo是认证的方法,当用户登陆的时候会调用,例如下面
@PostMapping("login")
public String login(String username, String password) {
try {
Subject subject = SecurityUtils.getSubject();
if (subject.isAuthenticated()) {
return "redirect:/static/html/indexLogin.html";
}
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
token.setRememberMe(true);
subject.login(token);
} catch (AuthenticationException e) {
return "redirect:/static/html/loginError.html";
}
return "redirect:/static/html/indexLogin.html";
}
- doGetAuthorizationInfo是授权的方法,在拦截器中进行权限校验的时候会调用
public class MyRealm extends AuthorizingRealm {
@Resource
private UserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
if (principals == null || StringUtils.isBlank((String) principals.getPrimaryPrincipal())) {
return null;
}
return new SimpleAuthorizationInfo(userService.queryUserRole((String) principals.getPrimaryPrincipal()));
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
if (token == null||StringUtils.isBlank((String) token.getPrincipal())) {
return null;
}
User user = userService.queryUserByName((String) token.getPrincipal());
if (user == null) {
return null;
}
return new SimpleAuthenticationInfo(
user.getUserName(), user.getPassword(), ByteSource.Util.bytes(user.getUserName()), getName());
}
- 在securityManager中注入realm,其中authenticator必须先于realms注入,这一点非常关键,我之前无论如何都无法授权,debug发现authenticator中的realms为空
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="authenticator">
<bean class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
<property name="authenticationStrategy">
<bean class="org.apache.shiro.authc.pam.AllSuccessfulStrategy"/>
</property>
</bean>
</property>
<property name="realms">
<list>
<bean class="com.qunar.lfz.shiro.MyRealm">
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="MD5"/>
<property name="hashIterations" value="5"/>
</bean>
</property>
</bean>
</list>
</property>
</bean>
- PS:因为我们指定了用户的原密码通过5次md5加盐加密进行校验,这也就要求用户注册的时候存入数据库的密码也是经过5次md5加盐加密的。shiro提供了Md5Hash工具类,通过new Md5Hash("原密码", "盐值", 5).toString()查看加密后的密码。