springboot+shiro简单登录认证
模拟从数据库取信息
1、实体类
注:@Data节省了set、get方法。@AllArgsConstructor在@Data基础上有参构造。
@Data
@AllArgsConstructor
public class User {
private String id;
private String userName;
private String password;
/**
* 用户对应的角色集合
*/
private Set<Role> roles;
}
@Data
@AllArgsConstructor
public class Role {
private String id;
private String roleName;
//角色对应权限集合
private Set<Permissions> permissions;
}
@Data
@AllArgsConstructor
public class Permissions {
private String id;
private String permissionsName;
}
2、编写service层实现类模拟数据
/**
* 模拟数据库查询
*
* @param userName 用户名
* @return User
*/
private User getMapByName(String userName) {
Permissions permissions1 = new Permissions("1", "query");
Permissions permissions2 = new Permissions("2", "add");
Set<Permissions> permissionsSet = new HashSet<>();
permissionsSet.add(permissions1);
permissionsSet.add(permissions2);
Role role = new Role("1", "admin", permissionsSet);
Set<Role> roleSet = new HashSet<>();
roleSet.add(role);
User user = new User("1", "wsl", "123456", roleSet);
Map<String, User> map = new HashMap<>();
map.put(user.getUserName(), user);
Set<Permissions> permissionsSet1 = new HashSet<>();
permissionsSet1.add(permissions1);
Role role1 = new Role("2", "user", permissionsSet1);
Set<Role> roleSet1 = new HashSet<>();
roleSet1.add(role1);
User user1 = new User("2", "zhangsan", "123456", roleSet1);
map.put(user1.getUserName(), user1);
return map.get(userName);
}
3、Realm代码
注:在获取账号操作,principals.getPrimaryPrincipal();这一步强转的对象是与下一个方法体中,new SimpleAuthenticationInfo(username,user.getPassword(),getName());第一个参数所对应。
public class UserRealm extends AuthorizingRealm {
@Autowired
private LoginService loginService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//获取登录账号
String username = (String) principals.getPrimaryPrincipal();
//获取登录账号的信息
User user = loginService.getUserByName(username);
//添加角色和权限
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
for(Role role:user.getRoles()){
//添加角色
simpleAuthorizationInfo.addRole(role.getRoleName());
//添加权限
for (Permissions permissions : role.getPermissions()){
simpleAuthorizationInfo.addStringPermission(permissions.getPermissionsName());
}
}
return simpleAuthorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
if (StringUtils.isEmpty(token.getPrincipal())){
return null;
}
//获取用户信息
String username = token.getPrincipal().toString();
User user = loginService.getUserByName(username);
if (user == null){
return null;
}else {
SimpleAuthenticationInfo simpleAuthorizationInfo =new SimpleAuthenticationInfo(
username,user.getPassword(),getName()
);
return simpleAuthorizationInfo;
}
}
}
4、配置shiro拦截器
@Configuration
public class ShiroConfig {
//@conditionalOnMissingBean,唯一bean,如果有相同的则该注解不生成。(个人理解)
@Bean
@ConditionalOnMissingBean
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
defaultAAP.setProxyTargetClass(true);
return defaultAAP;
}
@Bean(name = "shiroDialect")
public ShiroDialect shiroDialect(){
return new ShiroDialect();
}
//前面写的Realm(自己写的话换成自己的Realm)
@Bean
public UserRealm realm(){
return new UserRealm();
}
//权限管理
@Bean
public SecurityManager securityManager (){
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
defaultWebSecurityManager.setRealm(realm());
return defaultWebSecurityManager;
}
//Filer工厂,设置过滤
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String,String> map =new HashMap<>();
map.put("/","anon");
map.put("/loginOut","anon");
map.put("/**","authc");
//登录
shiroFilterFactoryBean.setLoginUrl("/login");
//成功
shiroFilterFactoryBean.setSuccessUrl("/index");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
//注入权限管理
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
5、Controller层
@Controller
public class LoginContorller {
@Autowired
private LoginService service;
@RequestMapping("/login")
public String login(HttpServletRequest request){
String username = request.getParameter("account");
String password = request.getParameter("password");
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(
username,password
);
try {
//进行验证,这里可以捕获异常,然后返回对应信息
subject.login(token);
} catch (UnknownAccountException e) {
return "用户名不存在!";
} catch (AuthenticationException e) {
return "账号或密码错误!";
} catch (AuthorizationException e) {
return "没有权限";
}
return "hello";
}
//Model是前端界面结合了点thymeleaf运用,可以不用考虑
@RequestMapping("/hello")
public String hello(Model model){
//存入数据
model.addAttribute("msg","<h1 style='color:red'>Hello</h1>");
model.addAttribute("users", Arrays.asList("小红", "小米","小白"));
return "hello";
}
}
6、前端界面
登录
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 4.0 Strict//EN" "TR/xhtml1/DTD/xhtml1-strict.dtd">
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<div><h1 id="say"></h1></div>
<div align="center">
<form action="/login" method="get">
<table>
<thead>
<th colspan="3" align="center">SpringBoot 登录</th>
</thead>
<tbody>
<tr >
<td >
<label for="account">账号:</label>
</td>
<td>
<input name="account" id="account" />
</td>
</tr>
<tr >
<td >
<label for="password">密码</label>
</td>
<td>
<input name="password" id="password" />
</td>
</tr>
<tr >
<td >
<input name="submit" type="submit" value="登录" />
</td>
<td>
<input name="reset" type="reset" value="重置" />
</td>
</tr>
</tbody>
</table>
</form>
</div>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
</body>
</html>
主界面
<!DOCTYPE html>
<html lang="en"
xmlns:shiro="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>success</h1>
<!--Thymeleaf语法:th:text就是将div中的内容设置为它指定的值-->
<div th:text="${msg}">你好</div>
<!--utext:会解析html,显示相应的效果-->
<div th:utext="${msg}">你好</div>
<!--each:遍历-->
<h3 th:each="user:${users}" th:text="${user}"></h3>
<h1>测试:<shiro:principal/></h1>
<shiro:hasPermission name="query">
用户[<shiro:principal/>]拥有权限
<br/>
</shiro:hasPermission>
<shiro:hasRole name="admin">
用户[<shiro:principal/>]拥有角色admin<br/>
</shiro:hasRole>
</body>
</html>
附上架包
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.10.2</version>
<scope>test</scope>
</dependency>
</dependencies>