一、简介
Web应用的安全管理,主要包括两个方面的内容:身份认证、用户授权,此处使用spring-cloud-security来说明。
二、依赖管理
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-security</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity4</artifactId> </dependency>
三、安全策略配置
Spring Security已经大体实现了,我们这里只是需要一些配置与引用。
package com.example.demo.config;
import com.example.demo.utils.security.CustomUserService;
import com.example.demo.utils.security.LoginSuccessHandler;
import com.example.demo.utils.security.MyFilterSecurityInterceptor;
import com.example.demo.utils.security.SecuritySettings;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
/**
* Security安全配置
*
* @Author: 我爱大金子
* @Description: Security安全配置
* @Date: Create in 15:20 2017/7/5
*/
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomFilterSecurityInterceptor customFilterSecurityInterceptor; // 权限管理过滤器
@Autowired
private SecuritySettings securitySettings; // 自定义安全配置类
/**注册UserDetailsService的bean*/
@Bean
public UserDetailsService customUserService(){
return new CustomUserService();
}
/**登录认证*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserService()); //userDetailsService验证
}
/***设置不拦截规则*/
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/js/**", "/css/**", "/images/**", "/druid/**");
}
/**安全策略配置*/
@Override
protected void configure(HttpSecurity http) throws Exception {
// 设置游客可以访问的URI
if (StringUtils.isNotBlank(securitySettings.getPermitall())) {
http.authorizeRequests().antMatchers(securitySettings.getPermitall().split(",")).permitAll();
}
http.authorizeRequests()
.anyRequest().authenticated() //任何请求,登录后可以访问
// 配置登录URI、登录失败跳转URI与登录成功后默认跳转URI
.and().formLogin().loginPage("/login").failureUrl("/login?error").permitAll().defaultSuccessUrl("/", true).successHandler(loginSuccessHandler())
// 注销行为任意访问
.and().logout().permitAll()
// 设置拒绝访问的提示URI
.and().exceptionHandling().accessDeniedPage("/login?illegal")
;
http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class);
}
/**登录成功处理器*/
private AuthenticationSuccessHandler loginSuccessHandler() {
return new LoginSuccessHandler();
}
}
说明:
loginPage:设置一个实验自定义的登录URI
loginSuccessHandler:设置自定义的登录处理器
permitAll:是允许访问
accessDeniedPage:配置拒绝访问的提示URI
antMatchers:对URI的配置
假设我要管理员才可以访问admin文件夹下的内容,如:.antMatchers("/admin/**").hasRole("ROLE_ADMIN"),
也可以设置admin文件夹下的文件可以有多个角色来访问,如:.antMatchers("/admin/**").hasAnyRole("ROLE_ADMIN","ROLE_USER")
也可以通过hasIpAddress来指定某一个ip可以访问该资源,写法如下.antMatchers("/admin/**").hasIpAddress("210.210.210.210")
3.1、自定义安全配置类
为是更方便的使用springSecurity,我们自定义一个权限的配置类,如配置登录的URI、游客访问的URI等配置项
package com.example.demo.utils.security;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* 自定义安全配置类
*
* @Author: 我爱大金子
* @Description: 自定义安全配置类
* @Date: Create in 9:45 2017/7/6
*/
@Configuration
@ConfigurationProperties(prefix = "securityConfig")
public class SecuritySettings {
/**允许访问的URL,多个用逗号分隔*/
private String permitall;
public String getPermitall() {
return permitall;
}
public void setPermitall(String permitall) {
this.permitall = permitall;
}
}
3.2、登录成功处理器
登录成功后,如果需要对用户的行为做一些记录或者执行其它操作,则可以使用登录成功处理器。
package com.example.demo.utils.security;
import com.example.demo.pojo.SysUser;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 登录成功处理器
*
* @Author: 我爱大金子
* @Description: 登录成功处理器
* @Date: Create in 11:35 2017/7/6
*/
public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
User userDetails = (User) authentication.getPrincipal();
System.out.println("登录用户:username=" + userDetails.getUsername() + ", uri=" + request.getContextPath());
super.onAuthenticationSuccess(request, response, authentication);
}
}
3.3、springMVC 配置(访问 /login 转向 login.html 页面)
package com.example.demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* springMVC 配置(注册访问 /login 转向 login.html 页面)
*
* @Author: 我爱大金子
* @Description: springMVC 配置(注册访问 /login 转向 login.html 页面)
* @Date: Create in 16:24 2017/7/5
*/
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
}
}
四、登录认证
在安全策略配置代码中有,主要看自定义的CustomUserService,此类实现了UserDetailsService接口,重写了loadUserByUsername方法
package com.example.demo.utils.security;
import com.example.demo.dao.SysPermissionDao;
import com.example.demo.dao.SysUserDao;
import com.example.demo.pojo.SysPermission;
import org.springframework.security.core.userdetails.User;
import com.example.demo.pojo.SysUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import java.util.ArrayList;
import java.util.List;
/**
* 自定义UserDetailsService,将用户权限交给springsecurity进行管控
*
* @Author: 我爱大金子
* @Description: 将用户权限交给Springsecurity进行管控
* @Date: Create in 16:19 2017/7/5
*/
public class CustomUserService implements UserDetailsService {
@Autowired
private SysUserDao sysUserDao;
@Autowired
private SysPermissionDao sysPermissionDao;
@Override
public UserDetails loadUserByUsername(String username) {
SysUser user = sysUserDao.findByUserName(username);
if (user != null) {
List<SysPermission> permissions = sysPermissionDao.findByAdminUserId(user.getId());
List<GrantedAuthority> grantedAuthorities = new ArrayList <>();
for (SysPermission permission : permissions) {
if (permission != null && permission.getName()!=null) {
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permission.getName());
//1:此处将权限信息添加到 GrantedAuthority 对象中,在后面进行全权限验证时会使用GrantedAuthority 对象。
grantedAuthorities.add(grantedAuthority);
}
}
return new User(user.getUsername(), user.getPassword(), grantedAuthorities);
} else {
throw new UsernameNotFoundException("admin: " + username + " do not exist!");
}
}
}
五、权限管理
在Security安全配置类中使用了权限管理过滤器CustomFilterSecurityInterceptor
package com.example.demo.utils.security;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.web.FilterInvocation;
import org.springframework.stereotype.Service;
import java.io.IOException;
/**
* 权限管理过滤器
*
* @Author: 我爱大金子
* @Description: 权限管理过滤器
* @Date: Create in 17:16 2017/7/5
*/
@Service
public class CustomFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
@Autowired
private CustomFilterInvocationSecurityMetadataSource customFilterInvocationSecurityMetadataSource; // 权限配置资源管理器
/**权限管理决断器*/
@Autowired
public void setMyAccessDecisionManager(CustomAccessDecisionManager customAccessDecisionManager) {
super.setAccessDecisionManager(customAccessDecisionManager);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
invoke(fi);
}
public void invoke(FilterInvocation fi) throws IOException, ServletException {
//fi里面有一个被拦截的url
//里面调用MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限
//再调用MyAccessDecisionManager的decide方法来校验用户的权限是否足够
InterceptorStatusToken token = super.beforeInvocation(fi);
try {
//执行下一个拦截器
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
} finally {
super.afterInvocation(token, null);
}
}
@Override
public void destroy() {
}
@Override
public Class<?> getSecureObjectClass() {
return FilterInvocation.class;
}
@Override
public SecurityMetadataSource obtainSecurityMetadataSource() {
return this.customFilterInvocationSecurityMetadataSource;
}
}
说明:
customFilterSecurityInterceptor:权限管理过滤器
customAccessDecisionManager:权限管理决断器
customFilterInvocationSecurityMetadataSource:权限配置资源管理器
其中过滤器在系统启动时开始工作,并同时导入权限配置资源管理器和权限管理决断器,对用户访问的资源进行管理。权限管理决断器对用户访问的资源与用户拥有的角色权限进行对比,以此来判断用户是否对某个资源具有访问权限。
5.1、权限管理过滤器
继承与AbstractSecurityInterceptor,实时监控用户的行为,防止用户访问未被授权的资源。
package com.example.demo.utils.security;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.web.FilterInvocation;
import org.springframework.stereotype.Service;
import java.io.IOException;
/**
* 权限管理过滤器
*
* @Author: 我爱大金子
* @Description: 权限管理过滤器
* @Date: Create in 17:16 2017/7/5
*/
@Service
public class CustomFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
Logger log = LoggerFactory.getLogger(CustomFilterSecurityInterceptor.class);
@Autowired
private CustomFilterInvocationSecurityMetadataSource customFilterInvocationSecurityMetadataSource; // 权限配置资源管理器
/**权限管理决断器*/
@Autowired
public void setMyAccessDecisionManager(CustomAccessDecisionManager customAccessDecisionManager) {
super.setAccessDecisionManager(customAccessDecisionManager);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
log.info("【权限管理过滤器】请求URL:" + fi.getRequestUrl());
invoke(fi);
}
public void invoke(FilterInvocation fi) throws IOException, ServletException {
//fi里面有一个被拦截的url
//里面调用CustomFilterInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限
//再调用CustomAccessDecisionManager的decide方法来校验用户的权限是否足够
InterceptorStatusToken token = super.beforeInvocation(fi);
try {
//执行下一个拦截器
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
} catch(Exception e) {
log.error("【权限管理过滤器】【异常】" + e.getMessage(), e);
} finally {
super.afterInvocation(token, null);
}
}
@Override
public void destroy() {
}
@Override
public Class<?> getSecureObjectClass() {
return FilterInvocation.class;
}
@Override
public SecurityMetadataSource obtainSecurityMetadataSource() {
return this.customFilterInvocationSecurityMetadataSource;
}
}
5.2、权限管理决断器
权限管理的关键部分就是决断器,它实现了AccessDecisionManager,重写了decide方法,使用自定义的决断器,在用户访问受保护的资源时,决断器判断用户拥有的角色中是否对改资源具有访问权限,如果没有,则拒绝访问
package com.example.demo.utils.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.Iterator;
/**
* 权限管理决断器
*
* @Author: 我爱大金子
* @Description: 权限管理决断器
* @Date: Create in 17:15 2017/7/5
*/
@Service
public class CustomAccessDecisionManager implements AccessDecisionManager {
Logger log = LoggerFactory.getLogger(CustomAccessDecisionManager.class);
// decide 方法是判定是否拥有权限的决策方法,
//authentication 是释CustomUserService中循环添加到 GrantedAuthority 对象中的权限信息集合.
//object 包含客户端发起的请求的requset信息,可转换为 HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
//configAttributes 为MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法返回的结果,此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
if(null== configAttributes || configAttributes.size() <=0) {
return;
}
ConfigAttribute c;
String needRole;
for(Iterator<ConfigAttribute> iter = configAttributes.iterator(); iter.hasNext(); ) {
c = iter.next();
needRole = c.getAttribute();
for(GrantedAuthority ga : authentication.getAuthorities()) {//authentication 为在注释1 中循环添加到 GrantedAuthority 对象中的权限信息集合
if(needRole.trim().equals(ga.getAuthority())) {
return;
}
}
log.info("【权限管理决断器】需要role:" + needRole);
}
throw new AccessDeniedException("Access is denied");
}
@Override
public boolean supports(ConfigAttribute attribute) {
return true;
}
@Override
public boolean supports(Class<?> clazz) {
return true;
}
}
5.3、权限配置资源管理器
权限配置资源管理器实现了FilterInvocationSecurityMetadataSource,在启动时就去加载了所有的权限列表,权限配置资源管理器为决断器实时提供支持,判断用户访问的资源是否在受保护的范围之内。
package com.example.demo.utils.security;
import com.example.demo.dao.SysPermissionDao;
import com.example.demo.pojo.SysPermission;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
/**
* 权限配置资源管理器
*
* @Author: 我爱大金子
* @Description: 权限配置资源管理器
* @Date: Create in 17:17 2017/7/5
*/
@Service
public class CustomFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
@Autowired
private SysPermissionDao sysPermissionDao;
private HashMap<String, Collection<ConfigAttribute>> map =null;
/**
* 加载权限表中所有权限
*/
public void loadResourceDefine(){
map = new HashMap<>();
Collection<ConfigAttribute> array;
ConfigAttribute cfg;
List<SysPermission> permissions = sysPermissionDao.findAll();
for(SysPermission permission : permissions) {
array = new ArrayList<>();
cfg = new SecurityConfig(permission.getName());
//此处只添加了用户的名字,其实还可以添加更多权限的信息,例如请求方法到ConfigAttribute的集合中去。此处添加的信息将会作为MyAccessDecisionManager类的decide的第三个参数。
array.add(cfg);
//用权限的getUrl() 作为map的key,用ConfigAttribute的集合作为 value,
map.put(permission.getUrl(), array);
}
}
//此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。
@Override
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
if(map ==null) loadResourceDefine();
//object 中包含用户请求的request 信息
HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
AntPathRequestMatcher matcher;
String resUrl;
for(Iterator<String> iter = map.keySet().iterator(); iter.hasNext(); ) {
resUrl = iter.next();
matcher = new AntPathRequestMatcher(resUrl);
if(matcher.matches(request)) {
return map.get(resUrl);
}
}
return null;
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class<?> clazz) {
return true;
}
}
六、根据权限设置连接
对于权限管理,我们可能希望,在一个用户访问的界面中,不是等到用户点击了超链接之后,才来判断用户有没有这个权限,而是按照用户拥有的权限来显示超链接。这样的设计对于用户体验来说,会更友好。
6.1、方法1:使用sec标签(thymeleaf)
在html标签中引入的Spring Security的标签:
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"
sec:authentication="name":取当前登录用户的用户名
<title sec:authentication="name"></title>
sec:authorize="hasRole('ROLE_ADMIN'):表示当前用户是否拥有角色ROLE_ADMIN
<li sec:authorize="hasRole('ROLE_ADMIN')"><a th:href="@{/admin}"> admin </a></li>
sec:authorize="hasAuthority('admin')":表示当前用户是否拥有权限admin
<li sec:authorize="hasAuthority('admin')"><a th:href="@{/admin}"> admin </a></li>
6.2、方法二:代码
在控制层用代码获取是否有权限,然后将标识放入内容中,页面获取处理
七、其它代码
7.1、controller
IndexController.java
package com.example.demo.controller;
import com.example.demo.domain.Msg;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 描述
*
* @Author: 我爱大金子
* @Description: 描述
* @Date: Create in 15:25 2017/7/5
*/
@Controller
public class IndexController {
/**系统首页*/
@RequestMapping("/")
public String index(Model model){
Msg msg = new Msg("测试标题","测试内容","欢迎来到HOME页面,您拥有index权限");
model.addAttribute("msg", msg);
return "home";
}
/**系统首页2*/
@RequestMapping("/index2")
public String index2(Model model){
Msg msg = new Msg("测试标题2","测试内容2","欢迎来到HOME页面,您拥有home权限");
model.addAttribute("msg", msg);
return "home";
}
@RequestMapping("/admin")
@ResponseBody
public String hello(){
return "hello admin";
}
@RequestMapping("/yk")
@ResponseBody
public String hello2(){
return "hello yk";
}
}
7.2、dao
SysUserDao.java
package com.example.demo.dao;
import com.example.demo.pojo.SysUser;
import org.apache.ibatis.annotations.Mapper;
/**
* 系统用户dao
*
* @Author: 我爱大金子
* @Description: 系统用户dao
* @Date: Create in 16:15 2017/7/5
*/
@Mapper
public interface SysUserDao {
public SysUser findByUserName(String username);
}
SysPermissionDao.java
package com.example.demo.dao;
import com.example.demo.pojo.SysPermission;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 系统权限dao
*
* @Author: 我爱大金子
* @Description: 描述
* @Date: Create in 17:05 2017/7/5
*/
@Mapper
public interface SysPermissionDao {
List<SysPermission> findAll();
List<SysPermission> findByAdminUserId(Long userId);
}
7.3、domain
Msg.java
package com.example.demo.domain;
/**
* 描述
*
* @Author: 我爱大金子
* @Description: 描述
* @Date: Create in 16:14 2017/7/5
*/
public class Msg {
private String title;
private String content;
private String etraInfo;
public Msg(String title, String content, String etraInfo) {
super();
this.title = title;
this.content = content;
this.etraInfo = etraInfo;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getEtraInfo() {
return etraInfo;
}
public void setEtraInfo(String etraInfo) {
this.etraInfo = etraInfo;
}
}
7.4、pojo
SysUser.java
package com.example.demo.pojo;
import java.util.List;
/**
* 系统用户
*
* @Author: 我爱大金子
* @Description: 系统用户
* @Date: Create in 16:12 2017/7/5
*/
public class SysUser {
private Long id;
private String username;
private String password;
private List<SysRole> roles;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public List<SysRole> getRoles() {
return roles;
}
public void setRoles(List<SysRole> roles) {
this.roles = roles;
}
}
SysRole.java
package com.example.demo.pojo;
/**
* 系统角色
*
* @Author: 我爱大金子
* @Description: 系统角色
* @Date: Create in 16:13 2017/7/5
*/
public class SysRole {
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
SysPermission.java
package com.example.demo.pojo;
/**
* 系统权限
*
* @Author: 我爱大金子
* @Description: 系统权限
* @Date: Create in 17:04 2017/7/5
*/
public class SysPermission {
private Long id;
//权限名称
private String name;
//权限描述
private String descritpion;
//授权链接
private String url;
//父节点id
private int pid;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescritpion() {
return descritpion;
}
public void setDescritpion(String descritpion) {
this.descritpion = descritpion;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getPid() {
return pid;
}
public void setPid(int pid) {
this.pid = pid;
}
}
7.5、mapperXX.xml
SysUserDao.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.example.demo.dao.SysUserDao" > <resultMap id="userMap" type="SysUser"> <id property="id" column="ID"/> <result property="username" column="username"/> <result property="password" column="PASSWORD"/> <collection property="roles" ofType="SysRole"> <result column="name" property="name"/> </collection> </resultMap> <select id="findByUserName" parameterType="String" resultMap="userMap"> select u.* ,r.name from sys_user u LEFT JOIN sys_user_role sru on u.id= sru.sys_user_id LEFT JOIN sys_role r on sru.sys_role_id=r.id where username= #{username} </select> </mapper>
SysPermissionDao.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.example.demo.dao.SysPermissionDao" > <select id="findAll" resultType="SysPermission"> SELECT * from sys_permission ; </select> <select id="findByAdminUserId" parameterType="java.lang.Long" resultType="SysPermission"> SELECT p.* FROM sys_user u LEFT JOIN sys_user_role sru ON u.id= sru.sys_user_id LEFT JOIN sys_role r ON sru.sys_role_id=r.id LEFT JOIN sys_role_permission spr ON spr.sys_role_id=r.id LEFT JOIN Sys_permission p ON p.id =spr.sys_permission_id WHERE u.id=#{userId} </select> </mapper>
7.6、html
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta content="text/html;charset=UTF-8"/>
<title>登录页面</title>
<link rel="stylesheet" th:href="@{css/bootstrap.min.css}"/>
<style type="text/css">
body {
padding-top: 50px;
}
.starter-template {
padding: 40px 15px;
text-align: center;
}
</style>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="#">Spring Security演示</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a th:href="@{/}"> 首页 </a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
<div class="container">
<div class="starter-template">
<p th:if="${param.logout}" class="bg-warning">已成功注销</p><!-- 1 -->
<p th:if="${param.illegal}" class="bg-warning">无权访问,请切换账号登录</p><!-- 1 -->
<p th:if="${param.error}" class="bg-danger">用户名或密码错误</p> <!-- 2 -->
<h2>使用账号密码登录</h2>
<form name="form" th:action="@{/login}" action="/login" method="POST"> <!-- 3 -->
<div class="form-group">
<label for="username">账号</label>
<input type="text" class="form-control" name="username" value="" placeholder="账号" />
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" class="form-control" name="password" placeholder="密码" />
</div>
<input type="submit" id="login" value="Login" class="btn btn-primary" />
</form>
</div>
</div>
</body>
</html>
home.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
<meta content="text/html;charset=UTF-8"/>
<title sec:authentication="name"></title>
<link rel="stylesheet" th:href="@{css/bootstrap.min.css}" />
<style type="text/css">
body {
padding-top: 50px;
}
.starter-template {
padding: 40px 15px;
text-align: center;
}
</style>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="#">Spring Security演示</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a th:href="@{/}"> 首页 </a></li>
<li sec:authorize="hasAuthority('admin')"><a th:href="@{/admin}"> admin </a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
<div class="container">
<div class="starter-template">
<h1 th:text="${msg.title}"></h1>
<p class="bg-primary" th:text="${msg.content}"></p>
<div>
<p class="bg-info" th:text="${msg.etraInfo}"></p>
</div>
<form th:action="@{/logout}" method="post">
<input type="submit" class="btn btn-primary" value="注销"/>
</form>
</div>
</div>
</body>
</html>
转载于:https://blog.51cto.com/1754966750/1945094