利用Shiro实现登录功能
Shiro简介
Refer: https://shiro.apache.org/
Features
Authentication: Sometimes referred to as ‘login’, this is the act of proving a user is who they say they are.
Authorization: The process of access control, i.e. determining ‘who’ has access to ‘what’.
Session Management: Managing user-specific sessions, even in non-web or EJB applications.
Cryptography: Keeping data secure using cryptographic algorithms while still being easy to use.
架构
High Level
Subject:用户主体
SecurityManager: Shiro核心, 管理所有的Subject 关联Realm
- Authentication
- Authorization
- Session Management
- Cache Management
- Realm coordination
- Event propagation
- “Remember Me” Services
- Subject creation
- Logout and more.
Realm: Shiro与加密数据数据的连接桥梁
Detail
Spring Boot与Shiro开发
导入依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.1</version>
</dependency>
编写Shiro配置类
定义Realm类
@Component
public class UserRealm extends AuthorizingRealm {
public UserRealm() {
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
return null;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
}
定义SecurityManager
@Bean
public SecurityManager securityManager(@Qualifier("userRealm") UserRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 配置 SecurityManager,并注入 shiroRealm
securityManager.setRealm(userRealm);
return securityManager;
}
定义Filter
Shiro内置Filter,可以实现权限相关的拦截器
常用Filter:
anon: 无需认证登录可以访问
authc:必须认证才可以访问
user:如果使用rememberMe的功能可以直接访问
perms:该资源必须得到资源权限才可以访问
role:该资源必须得到角色权限才可以访问
过滤器简称 | 对应的java类 |
---|---|
anon | org.apache.shiro.web.filter.authc.AnonymousFilter |
authc | org.apache.shiro.web.filter.authc.FormAuthenticationFilter |
authcBasic | org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter |
perms | org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter |
port | org.apache.shiro.web.filter.authz.PortFilter |
rest | org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter |
roles | org.apache.shiro.web.filter.authz.RolesAuthorizationFilter |
ssl | org.apache.shiro.web.filter.authz.SslFilter |
user | org.apache.shiro.web.filter.authc.UserFilter |
logout | org.apache.shiro.web.filter.authc.LogoutFilter |
/**
* ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
val shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
val filterChainDefinitionMap = new LinkedHashMap<String, String>(); // order
filterChainDefinitionMap.put("/v1.0/session", "anon");
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
用户登录
UserManagerImpl login
@Override
public void login(String username, String password) {
// Get Subject
val subject = SecurityUtils.getSubject();
// Generate Token
val token = new UsernamePasswordToken(username, password);
subject.login(token);
}
SessionController
@RestController
@RequestMapping("v1.0/session")
public class SessionControllerV1 {
@Autowired
private UserInfoManager userInfoManager;
@PostMapping()
public String login(@RequestParam("username") String username,
@RequestParam("password") String password) {
userInfoManager.login(username, password);
return "success";
}
}
UserRealm doGetAuthenticationInfo
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal();
String password = new String((char[]) token.getCredentials());
if (username == null || username.isEmpty() || !username.equals("hardcore")) {
throw new UnknownAccountException("unknown");
}
if (!password.equals("hardcore")) {
throw new IncorrectCredentialsException("password is invalid");
}
return new SimpleAuthenticationInfo(username, password, null, this.getName());
}
Login过程源码分析
连接数据库
从数据库中获取信息
doGetAuthenticationInfo中通过userManager
String username = (String) token.getPrincipal();
String password = new String((char[]) token.getCredentials());
val userInfo = userInfoManager.getUserInfoByUserId(1L);
if (!password.equals(userInfo.getPassword())) {
throw new IncorrectCredentialsException("password is invalid");
}
return new SimpleAuthenticationInfo(userInfo.getUsername(), userInfo.getPassword(), null, this.getName());
POST http://localhost:8080/users/login
{
"username": "zg",
"password": "123456,
}
Output: success
相关文章
- 基于-SLF4J-MDC-机制的日志链路追踪配置属性
ums: # ================ 基于 SLF4J MDC 机制的日志链路追踪配置属性 ================ mdc: # 是否支持基于 SLF4J MDC
- ajax-跨域访问
ajax 跨域访问 <!DOCTYPE html> <html xmlns:th="http://www.w3.org/1999/xhtml"> <head>
- 给第三方登录时用的数据库表-user_connection-与-auth_token-添加-redis-cache
spring: # 设置缓存为 Redis cache: type: redis # redis redis: host: 192.168.88.88 port
- Java动态代理
Jdk动态代理 通过InvocationHandler和Proxy针对实现了接口的类进行动态代理,即必须有相应的接口 应用 public class TestProxy { public
- Java读取classpath中的文件
public void init() { try { //URL url = Thread.currentThread().getContextClassLo
随机推荐
- 基于-SLF4J-MDC-机制的日志链路追踪配置属性
ums: # ================ 基于 SLF4J MDC 机制的日志链路追踪配置属性 ================ mdc: # 是否支持基于 SLF4J MDC
- ajax-跨域访问
ajax 跨域访问 <!DOCTYPE html> <html xmlns:th="http://www.w3.org/1999/xhtml"> <head>
- 给第三方登录时用的数据库表-user_connection-与-auth_token-添加-redis-cache
spring: # 设置缓存为 Redis cache: type: redis # redis redis: host: 192.168.88.88 port
- Java动态代理
Jdk动态代理 通过InvocationHandler和Proxy针对实现了接口的类进行动态代理,即必须有相应的接口 应用 public class TestProxy { public
- Java读取classpath中的文件
public void init() { try { //URL url = Thread.currentThread().getContextClassLo